![JAR search and dependency download from the Maven repository](/logo.png)
commonMain.ru.casperix.math.angle.float32.RadianFloat.kt Maven / Gradle / Ivy
package ru.casperix.math.angle.float32
import ru.casperix.math.angle.Angle
import ru.casperix.math.angle.AngleBuilder
import ru.casperix.math.angle.float64.RadianDouble
import ru.casperix.math.geometry.fHPI
import ru.casperix.math.geometry.fPI
import ru.casperix.math.geometry.fPI2
import ru.casperix.math.geometry.fRADIAN_TO_DEGREE
import ru.casperix.math.interpolation.float32.InterpolateFloatFunction
import ru.casperix.math.interpolation.float32.linearInterpolatef
import ru.casperix.math.vector.float32.Vector2f
import ru.casperix.misc.toPrecision
import kotlinx.serialization.Serializable
import kotlin.jvm.JvmInline
import kotlin.math.*
@JvmInline
@Serializable
value class RadianFloat(val value: Float) : ru.casperix.math.angle.Angle {
/**
* @return angle in [0, 2PI) interval
*/
override fun normalize(): RadianFloat {
return RadianFloat(absMod(value, fPI2))
}
override fun isFinite(): Boolean {
return value.isFinite()
}
override operator fun plus(other: RadianFloat): RadianFloat {
return RadianFloat(value + other.value)
}
override operator fun minus(other: RadianFloat): RadianFloat {
return RadianFloat(value - other.value)
}
override operator fun plus(other: Float): RadianFloat {
return RadianFloat(value + other)
}
override operator fun minus(other: Float): RadianFloat {
return RadianFloat(value - other)
}
override operator fun unaryMinus(): RadianFloat {
return RadianFloat(-value)
}
override operator fun times(factor: Float): RadianFloat {
return RadianFloat(value * factor)
}
override operator fun div(factor: Float): RadianFloat {
return RadianFloat(value / factor)
}
override operator fun compareTo(other: Float): Int {
return value.compareTo(other)
}
override operator fun compareTo(other: RadianFloat): Int {
return value.compareTo(other.value)
}
fun toDegree(): ru.casperix.math.angle.float32.DegreeFloat {
return ru.casperix.math.angle.float32.DegreeFloat(value * fRADIAN_TO_DEGREE)
}
fun toRadianDouble(): RadianDouble {
return RadianDouble(value.toDouble())
}
override fun format(precision: Int): String {
return value.toPrecision(precision)
}
override fun toString(): String {
return format(3)
}
fun toDirection(): Vector2f {
return Vector2f(cos(value), sin(value))
}
fun distTo(other: RadianFloat): RadianFloat {
return betweenAngle(this, other)
}
companion object : ru.casperix.math.angle.AngleBuilder {
override val ZERO = RadianFloat(0f)
val PI2 = RadianFloat(fPI2)
val PI = RadianFloat(fPI)
val HPI = RadianFloat(fHPI)
override val MAX = PI2
/**
* @see [byDirectionRadian]
*/
override fun byDirection(value: Vector2f): RadianFloat {
return byDirection(value.x, value.y)
}
/**
* @see [byDirectionRadian]
*/
override fun byDirection(x: Float, y: Float): RadianFloat {
return RadianFloat(byDirectionRadian(x, y))
}
/**
* @return angle from X-axis to vector in [0, 2PI) interval
*/
fun byDirectionRadian(x: Float, y: Float): Float {
val result = atan2(y, x)
return if (result < 0f) PI2.value + result
else result
// val xAbs = x.absoluteValue
// val yAbs = y.absoluteValue
// return (fPI - fHPI * (1f + x.sign) * (1f - (y * y).sign) - fHPI / 2f * (2f + x.sign) * y.sign - (x * y).sign * atan((xAbs - yAbs) / (xAbs + yAbs)))
}
fun absMod(value: Float, mod: Float): Float {
return if (value < 0f) {
(mod - (-value) % mod) % mod
} else {
value % mod
}
}
/**
* @return angle in [0, 2PI) interval
*/
fun interpolateAngular(
start: RadianFloat,
finish: RadianFloat,
position: Float,
interpolator: InterpolateFloatFunction = linearInterpolatef
): RadianFloat {
val startNormalized = start.normalize().value
val finishNormalized = finish.normalize().value
val finishAdapted = if ((startNormalized - finishNormalized).absoluteValue <= fPI) {
finishNormalized
} else if (startNormalized > finishNormalized) {
finishNormalized + fPI2
} else {
finishNormalized - fPI2
}
return RadianFloat(interpolator(startNormalized, finishAdapted, position)).normalize()
}
fun betweenDirections(directionA: Vector2f, directionB: Vector2f): RadianFloat {
return betweenAngle(byDirection(directionA), byDirection(directionB))
}
fun betweenAngle(angleA: RadianFloat, angleB: RadianFloat): RadianFloat {
val a = (angleB - angleA).normalize()
val b = (angleA - angleB).normalize()
return if (a.value <= b.value) a else b
}
fun betweenDirectionsDirected(directionA: Vector2f, directionB: Vector2f): RadianFloat {
return betweenAnglesDirected(byDirection(directionA), byDirection(directionB))
}
/**
* Radial distance from angle-a to angle-b in counter-clock-wise direction
*/
fun betweenAnglesDirected(angleA: RadianFloat, angleB: RadianFloat): RadianFloat {
val adaptedA = angleA.normalize()
var adaptedB = angleB.normalize()
if (adaptedB < adaptedA) {
adaptedB += MAX
}
return adaptedB - adaptedA
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy