commonMain.ru.casperix.math.angle.float64.DegreeDouble.kt Maven / Gradle / Ivy
package ru.casperix.math.angle.float64
import ru.casperix.math.angle.Angle
import ru.casperix.math.angle.AngleBuilder
import ru.casperix.math.angle.float32.DegreeFloat
import ru.casperix.math.angle.float64.RadianDouble.Companion.byDirectionRadian
import ru.casperix.math.geometry.DEGREE_TO_RADIAN
import ru.casperix.math.geometry.RADIAN_TO_DEGREE
import ru.casperix.math.interpolation.float64.InterpolateDoubleFunction
import ru.casperix.math.interpolation.float64.linearInterpolate
import ru.casperix.math.vector.float32.Vector2f
import ru.casperix.math.vector.float64.Vector2d
import ru.casperix.misc.toPrecision
import kotlinx.serialization.Serializable
import kotlin.jvm.JvmInline
import kotlin.math.absoluteValue
@JvmInline
@Serializable
value class DegreeDouble(val value: Double) : ru.casperix.math.angle.Angle {
/**
* @return angle in [0, 360) interval
*/
override fun normalize(): DegreeDouble {
return DegreeDouble(absMod(value, 360.0))
}
override fun isFinite(): Boolean {
return value.isFinite()
}
fun toRadian(): RadianDouble {
return RadianDouble(value * DEGREE_TO_RADIAN)
}
fun toDegreeFloat(): ru.casperix.math.angle.float32.DegreeFloat {
return ru.casperix.math.angle.float32.DegreeFloat(value.toFloat())
}
override operator fun plus(other: DegreeDouble): DegreeDouble {
return DegreeDouble(value + other.value)
}
override operator fun minus(other: DegreeDouble): DegreeDouble {
return DegreeDouble(value - other.value)
}
override operator fun plus(other: Double): DegreeDouble {
return DegreeDouble(value + other)
}
override operator fun minus(other: Double): DegreeDouble {
return DegreeDouble(value - other)
}
override operator fun unaryMinus(): DegreeDouble {
return DegreeDouble(-value)
}
override operator fun times(factor: Double): DegreeDouble {
return DegreeDouble(value * factor)
}
override operator fun div(factor: Double): DegreeDouble {
return DegreeDouble(value / factor)
}
override operator fun compareTo(other: Double): Int {
return value.compareTo(other)
}
override operator fun compareTo(other: DegreeDouble): Int {
return value.compareTo(other.value)
}
override fun format(precision:Int):String {
return value.toPrecision(precision) + '°'
}
override fun toString(): String {
return format(1)
}
fun toDirection(): Vector2d {
return toRadian().toDirection()
}
fun distTo(other: DegreeDouble): DegreeDouble {
return betweenAngle(this, other)
}
companion object : ru.casperix.math.angle.AngleBuilder {
override val ZERO = DegreeDouble(0.0)
override val MAX = DegreeDouble(360.0)
val HALF = DegreeDouble(180.0)
val QUARTER = DegreeDouble(90.0)
private fun absMod(value: Double, mod: Double): Double {
return if (value < 0.0) {
(mod - (-value) % mod) % mod
} else {
value % mod
}
}
/**
* @return angle from X-axis to vector in [-180, 180) interval
*/
override fun byDirection(x: Double, y: Double): DegreeDouble {
return DegreeDouble(byDirectionRadian(x, y) * RADIAN_TO_DEGREE)
}
override fun byDirection(value: Vector2d): DegreeDouble {
return byDirection(value.x, value.y)
}
fun interpolateAngular(
a: DegreeDouble,
b: DegreeDouble,
weightB: Double,
interpolator: InterpolateDoubleFunction = linearInterpolate
): DegreeDouble {
val startNormalized = a.normalize().value
val finishNormalized = b.normalize().value
val finishAdapted = if ((startNormalized - finishNormalized).absoluteValue <= 180f) {
finishNormalized
} else if (startNormalized > finishNormalized) {
finishNormalized + 360f
} else {
finishNormalized - 360f
}
return DegreeDouble(interpolator(startNormalized, finishAdapted, weightB)).normalize()
}
fun betweenAngle(a: DegreeDouble, b: DegreeDouble): DegreeDouble {
val startNormalized = a.normalize().value
val finishNormalized = b.normalize().value
val finishAdapted = if ((startNormalized - finishNormalized).absoluteValue <= 180.0) {
finishNormalized
} else if (startNormalized > finishNormalized) {
finishNormalized + 360.0
} else {
finishNormalized - 360.0
}
return DegreeDouble((startNormalized - finishAdapted).absoluteValue).normalize()
}
// fun angularDest(directionA: Vector2f, directionB: Vector2f): Float {
// return angularDest(getAngle(directionA), getAngle(directionB))
// }
//
// fun angularDest(angleA: Float, angleB: Float): Float {
// return min(
// normalize(angleB - angleA),
// normalize(angleA - angleB),
// )
// }
}
}