diff options
| author | David Göransson <david.goransson90@gmail.com> | 2024-02-13 16:21:28 +0100 |
|---|---|---|
| committer | David Göransson <david.goransson90@gmail.com> | 2024-02-15 13:58:29 +0100 |
| commit | c6157ee0ce96e4fbb0657bc7cac21c817093461c (patch) | |
| tree | 09d889154ca5e32367b51a4952b8760371d6da10 /android/lib/model/src | |
| parent | 34b5e9ed46b436a1fa4a5025aa136b7c88b4ede5 (diff) | |
| download | mullvadvpn-c6157ee0ce96e4fbb0657bc7cac21c817093461c.tar.xz mullvadvpn-c6157ee0ce96e4fbb0657bc7cac21c817093461c.zip | |
Add Latitude, Longitude and LatLong to model
Diffstat (limited to 'android/lib/model/src')
3 files changed, 131 insertions, 0 deletions
diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/LatLong.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/LatLong.kt new file mode 100644 index 0000000000..ae047130e8 --- /dev/null +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/LatLong.kt @@ -0,0 +1,21 @@ +package net.mullvad.mullvadvpn.model + +import kotlin.math.pow +import kotlin.math.sqrt + +data class LatLong(val latitude: Latitude, val longitude: Longitude) { + + fun distanceTo(other: LatLong): Float = + sqrt( + latitude.distanceTo(other.latitude).pow(2f) + + (longitude.distanceTo(other.longitude).pow(2f)) + ) + + operator fun plus(other: LatLong) = + LatLong(latitude + other.latitude, longitude + other.longitude) + + operator fun minus(other: LatLong) = + LatLong(latitude - other.latitude, longitude - other.longitude) +} + +const val COMPLETE_ANGLE = 360f diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Latitude.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Latitude.kt new file mode 100644 index 0000000000..14c5b66983 --- /dev/null +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Latitude.kt @@ -0,0 +1,55 @@ +package net.mullvad.mullvadvpn.model + +import kotlin.math.absoluteValue + +@JvmInline +value class Latitude(val value: Float) { + init { + require(value in LATITUDE_RANGE) { + "Latitude: '$value' must be between $MIN_LATITUDE_VALUE and $MAX_LATITUDE_VALUE" + } + } + + fun distanceTo(other: Latitude) = (other.value - value).absoluteValue + + operator fun plus(other: Latitude) = fromFloat(value + other.value) + + operator fun minus(other: Latitude) = fromFloat(value - other.value) + + companion object { + private const val MIN_LATITUDE_VALUE: Float = -90f + private const val MAX_LATITUDE_VALUE: Float = 90f + private val LATITUDE_RANGE = MIN_LATITUDE_VALUE..MAX_LATITUDE_VALUE + + /** + * Create a [Latitude] from a float value. + * + * This function will unwind a float to a valid latitude value. E.g 190 will be unwound to + * -10 and 360 will be unwound to 0. + */ + fun fromFloat(value: Float): Latitude { + val unwoundValue = unwind(value) + return Latitude(unwoundValue) + } + + private fun unwind(value: Float): Float { + // Remove all 360 degrees + val withoutRotations = value % COMPLETE_ANGLE + + // If we are above 180 or below -180, we wrapped half a turn and need to flip sign + val partiallyUnwound = + if (withoutRotations.absoluteValue > COMPLETE_ANGLE / 2) { + -withoutRotations % (COMPLETE_ANGLE / 2) + } else withoutRotations + + return when { + partiallyUnwound < MIN_LATITUDE_VALUE -> + MIN_LATITUDE_VALUE - (partiallyUnwound % MIN_LATITUDE_VALUE) + partiallyUnwound > MAX_LATITUDE_VALUE -> + MAX_LATITUDE_VALUE - (partiallyUnwound % MAX_LATITUDE_VALUE) + // partiallyUnwound in range MIN_LATITUDE_VALUE..MAX_LATITUDE_VALUE + else -> partiallyUnwound + } + } + } +} diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Longitude.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Longitude.kt new file mode 100644 index 0000000000..9f73a6ff17 --- /dev/null +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Longitude.kt @@ -0,0 +1,55 @@ +package net.mullvad.mullvadvpn.model + +import kotlin.math.absoluteValue + +@JvmInline +value class Longitude(val value: Float) { + init { + require(value in LONGITUDE_RANGE) { + "Longitude: '$value' must be between $MIN_LONGITUDE_VALUE and $MAX_LONGITUDE_VALUE" + } + } + + fun distanceTo(other: Longitude) = vectorTo(other).value.absoluteValue + + fun vectorTo(other: Longitude): Longitude { + val diff = other.value - value + val vectorValue = + when { + diff > MAX_LONGITUDE_VALUE -> diff - COMPLETE_ANGLE + diff < MIN_LONGITUDE_VALUE -> diff + COMPLETE_ANGLE + else -> diff + } + return Longitude(vectorValue) + } + + operator fun plus(other: Longitude) = fromFloat(value + other.value) + + operator fun minus(other: Longitude) = fromFloat(value - other.value) + + companion object { + private const val MIN_LONGITUDE_VALUE: Float = -180f + private const val MAX_LONGITUDE_VALUE: Float = 180f + private val LONGITUDE_RANGE = MIN_LONGITUDE_VALUE..MAX_LONGITUDE_VALUE + + /** + * Create a [Longitude] from a float value. + * + * This function will unwind a float to a valid longitude value. E.g 190 will be unwound to + * -170 and 360 will be unwound to 0. + */ + fun fromFloat(value: Float): Longitude { + val unwoundValue = unwind(value) + return Longitude(unwoundValue) + } + + private fun unwind(value: Float): Float { + val unwound = value % COMPLETE_ANGLE + return when { + unwound > MAX_LONGITUDE_VALUE -> unwound - COMPLETE_ANGLE + unwound < MIN_LONGITUDE_VALUE -> unwound + COMPLETE_ANGLE + else -> unwound + } + } + } +} |
