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

commonMain.ru.casperix.math.curve.float64.BezierCubic2d.kt Maven / Gradle / Ivy

package ru.casperix.math.curve.float64

import ru.casperix.math.curve.CurveHelper
import ru.casperix.math.interpolation.float64.InterpolationDouble
import ru.casperix.math.vector.float64.Vector2d
import kotlinx.serialization.Serializable
import kotlin.math.pow

@Serializable
data class BezierCubic2d(val p0: Vector2d, val p1: Vector2d, val p2: Vector2d, val p3: Vector2d) :
    LazyCurve2d() {
    override fun getPosition(t: Double): Vector2d {
        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 Vector2d(
            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(): Double {
        return CurveHelper.calculateLength(this, 10)
    }

    fun translate(offset: Vector2d): BezierCubic2d {
        return BezierCubic2d(p0 + offset, p1 + offset, p2 + offset, p3 + offset)
    }

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

        val L0 = p0
        val R3 = p3

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

        val R2 = InterpolationDouble.vector2(p2, p3, t)
        val R1 = InterpolationDouble.vector2(H, R2, t)

        val R0 = InterpolationDouble.vector2(L2, R1, t)
        val L3 = R0

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

    override fun getTangent(t: Double): Vector2d {
        return Vector2d(
            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: Double, a: Double, b: Double, c: Double, d: Double): Double {
        val C1 = d - 3.0 * c + 3.0 * b - a
        val C2 = 3.0 * c - 6.0 * b + 3.0 * a
        val C3 = 3.0 * b - 3.0 * a

        return 3.0 * C1 * t * t + 2.0 * C2 * t + C3
    }

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

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy