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

commonMain.ru.casperix.math.curve.float32.BezierCubic2f.kt Maven / Gradle / Ivy

package ru.casperix.math.curve.float32

import ru.casperix.math.curve.CurveHelper
import ru.casperix.math.interpolation.float32.InterpolationFloat
import ru.casperix.math.vector.float32.Vector2f
import kotlinx.serialization.Serializable
import kotlin.math.pow

@Serializable
data class BezierCubic2f(val p0: Vector2f, val p1: Vector2f, val p2: Vector2f, val p3: Vector2f) :
    ParametricCurve2f {
    override fun getPosition(t: Float): Vector2f {
        val s = 1f - t
        val k0 = s.pow(3)
        val k1 = 3 * t * s.pow(2)
        val k2 = 3f * t.pow(2) * s
        val k3 = t.pow(3)
        return Vector2f(
            p0.x * k0 + p1.x * k1 + p2.x * k2 + p3.x * k3,
            p0.y * k0 + p1.y * k1 + p2.y * k2 + p3.y * k3,
        )
    }

    override fun length(): Float {
        return CurveHelper.calculateLength(this, 10)
    }

    fun translate(offset: Vector2f): BezierCubic2f {
        return BezierCubic2f(p0 + offset, p1 + offset, p2 + offset, p3 + offset)
    }

    override fun divide(t: Float): Pair {
        val H = InterpolationFloat.vector2(p1, p2, t)

        val L0 = p0
        val R3 = p3

        val L1 = InterpolationFloat.vector2(p0, p1, t)
        val L2 = InterpolationFloat.vector2(L1, H, t)

        val R2 = InterpolationFloat.vector2(p2, p3, t)
        val R1 = InterpolationFloat.vector2(H, R2, t)
        val R0 = InterpolationFloat.vector2(L2, R1, t)

        val L3 = R0

        return Pair(BezierCubic2f(L0, L1, L2, L3), BezierCubic2f(R0, R1, R2, R3))
    }

    override fun getTangent(t: Float): Vector2f {
        return Vector2f(
            bezierTangent(t, p0.x, p1.x, p2.x, p3.x),
            bezierTangent(t, p0.y, p1.y, p2.y, p3.y),
        ).normalize()
    }


    /**
     * https://stackoverflow.com/questions/4089443/find-the-tangent-of-a-point-on-a-cubic-bezier-curve
     */
    private fun bezierTangent(t: Float, a: Float, b: Float, c: Float, d: Float): Float {
        val C1 = d - 3f * c + 3f * b - a
        val C2 = 3f * c - 6f * b + 3f * a
        val C3 = 3f * b - 3f * a

        return 3f * C1 * t * t + 2f * C2 * t + C3
    }

    companion object {
        fun byDirection(
            start: Vector2f,
            startDirection: Vector2f,
            finish: Vector2f,
            finishDirection: Vector2f
        ): BezierCubic2f {
            return BezierCubic2f(start, start + startDirection, finish - finishDirection, finish)
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy