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

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),
//            )
//        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy