All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.casperix.math.angle.float32.DegreeFloat.kt Maven / Gradle / Ivy

package casperix.math.angle.float32

import casperix.math.angle.Angle
import casperix.math.angle.AngleBuilder
import casperix.math.angle.float64.DegreeDouble
import casperix.math.geometry.*
import casperix.math.interpolation.float32.InterpolateFloatFunction
import casperix.math.interpolation.float32.linearInterpolatef
import casperix.math.vector.float32.Vector2f
import casperix.misc.toPrecision
import kotlinx.serialization.Serializable
import kotlin.jvm.JvmInline
import kotlin.math.absoluteValue

@JvmInline
@Serializable
value class DegreeFloat(val value: Float) : Angle {
    /**
     * @return angle in [0, 360) interval
     */
    override fun normalize(): DegreeFloat {
        return DegreeFloat(absMod(value, 360f))
    }

    override fun isFinite(): Boolean {
        return value.isFinite()
    }

    fun toRadian(): RadianFloat {
        return RadianFloat(value * fDEGREE_TO_RADIAN)
    }

    fun toDegreeDouble(): DegreeDouble {
        return DegreeDouble(value.toDouble())
    }

    override operator fun plus(other: DegreeFloat): DegreeFloat {
        return DegreeFloat(value + other.value)
    }

    override operator fun minus(other: DegreeFloat): DegreeFloat {
        return DegreeFloat(value - other.value)
    }

    override operator fun plus(other: Float): DegreeFloat {
        return DegreeFloat(value + other)
    }

    override operator fun minus(other: Float): DegreeFloat {
        return DegreeFloat(value - other)
    }

    override operator fun unaryMinus(): DegreeFloat {
        return DegreeFloat(-value)
    }

    override operator fun times(factor: Float): DegreeFloat {
        return DegreeFloat(value * factor)
    }

    override operator fun div(factor: Float): DegreeFloat {
        return DegreeFloat(value / factor)
    }

    override operator fun compareTo(other: Float): Int {
        return value.compareTo(other)
    }

    override operator fun compareTo(other: DegreeFloat): 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():Vector2f {
        return toRadian().toDirection()
    }

    fun distTo(other: DegreeFloat): DegreeFloat {
        return betweenAngles(this, other)
    }

    companion object : AngleBuilder {
        override val ZERO = DegreeFloat(0f)
        override val MAX = DegreeFloat(360f)
        val HALF = DegreeFloat(180f)
        val QUARTER = DegreeFloat(90f)


        private fun absMod(value: Float, mod: Float): Float {
            return if (value < 0f) {
                (mod - (-value) % mod) % mod
            } else {
                value % mod
            }
        }

        /**
         * @return angle from X-axis to vector in [-180, 180) interval
         */
        override fun byDirection(x: Float, y: Float): DegreeFloat {
            return DegreeFloat(RadianFloat.byDirectionRadian(x, y) * fRADIAN_TO_DEGREE)
        }

        override fun byDirection(value: Vector2f): DegreeFloat {
            return byDirection(value.x, value.y)
        }

        fun interpolateAngular(
            a: DegreeFloat,
            b: DegreeFloat,
            weightB: Float,
            interpolator: InterpolateFloatFunction = linearInterpolatef
        ): DegreeFloat {
            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 DegreeFloat(interpolator(startNormalized, finishAdapted, weightB)).normalize()
        }

        fun betweenDirections(directionA: Vector2f, directionB: Vector2f): DegreeFloat {
            return betweenAngles(byDirection(directionA), byDirection(directionB))
        }

        fun betweenAngles(angleA: DegreeFloat, angleB: DegreeFloat): DegreeFloat {
            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): DegreeFloat {
            return betweenAnglesDirected(byDirection(directionA), byDirection(directionB))
        }

        /**
         *  Radial distance from angle-a to angle-b in counter-clock-wise direction
         */
        fun betweenAnglesDirected(angleA: DegreeFloat, angleB: DegreeFloat): DegreeFloat {
            val adaptedA = angleA.normalize()
            var adaptedB = angleB.normalize()
            if (adaptedB < adaptedA) {
                adaptedB += MAX
            }

            return adaptedB - adaptedA
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy