美文网首页
贝塞尔曲线规则详解

贝塞尔曲线规则详解

作者: Lucky胡 | 来源:发表于2019-11-07 17:25 被阅读0次

概念

贝塞尔曲线是用一系列点来控制曲线状态的,我们将这些点简单分为两类,一类是控制点,一类是数据点

1、一阶贝塞尔曲线
一阶贝塞尔曲线没有控制点,只有两个数据点。最终的效果为一条直线。


一阶贝塞尔曲线

2、二阶贝塞尔曲线
由两个数据点(点A和点C)和一个控制点(点B)来描述曲线状态。


二阶贝塞尔曲线

3、三阶贝塞尔曲线
由两个数据点和两个控制点来描述曲线状态。

三阶贝塞尔曲线

计算方法

贝塞尔曲线计算公式

在计算贝塞尔公式时,用到了德卡斯特利奥算法:

//其中,i为阶数,j为第几个点,t为时间(即走过的路程,0~1之间)
p(i, j) = (1 - t) * p(i - 1, j) + t * p(i - 1, j + 1)

在编写代码计算时,可以利用递归进行计算。

class BezierUtils(private var points: List<PointF>) {
    /**
     * 德卡斯特利奥算法,计算贝塞尔曲线
     * @param i 贝塞尔曲线阶数
     * @param j 控制点
     * @param t 时间
     * @return
     */
    fun deCasteljauX(i: Int, j: Int, t: Float): Float {
        if (i == 1) {
            return (1 - t) * points[j].x + t * points[j+1].x
        }
        return (1-t) * deCasteljauX(i-1,j,t) + t*deCasteljauX(i-1,j+1,t)
    }

    /**
     * 德卡斯特利奥算法,计算贝塞尔曲线
     * @param i 贝塞尔曲线阶数
     * @param j 控制点
     * @param t 时间
     * @return
     */
    fun deCasteljauY(i: Int, j: Int, t: Float): Float {
        if (i == 1) {
            return (1 - t) * points[j].y + t * points[j+1].y
        }
        return (1-t) * deCasteljauX(i-1,j,t) + t*deCasteljauX(i-1,j+1,t)
    }
}

一个简单的绘制任意阶贝塞尔曲线的Demo:

class BezierView(context: Context?, attrs: AttributeSet?) : BaseView(context, attrs) {

    lateinit var points: ArrayList<PointF>

    lateinit var path: Path

    var bezierUtils: BezierUtils

    init {
        init()
        bezierUtils = BezierUtils(points)
    }

    fun init() {
        points = arrayListOf()
        var order = 5

        for (i in 1..order) {
            var p = PointF()
            p.x = (100f + Math.random() * 800f).toFloat()
            p.y = (100f + Math.random() * 800f).toFloat()
            points.add(p)
        }
        path = Path()
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        var i = 0
        paint.color = Color.GRAY
        for (p in points) {
            if (i == 0) {
                path.moveTo(p.x, p.y)
            } else {
                path.lineTo(p.x, p.y)
            }
            I++
            canvas?.drawCircle(p.x, p.y, 10f, paint)
        }
        canvas?.drawPath(path, paint)

        paint.color = Color.RED
        drawBezier()
        canvas?.drawPath(path, paint)
        path.reset()
    }

    private fun drawBezier() {
        path.reset()
        bezierUtils.setPoints(points)
        var t = 0f
        for (i in 0..1000) {
            if (i == 0) {
                path.moveTo(points[0].x, points[0].y)
            }

            t = (i * 0.001).toFloat()

            var x = bezierUtils.deCasteljauX(points.size - 1, 0, t)
            var y = bezierUtils.deCasteljauY(points.size - 1, 0, t)
            path.lineTo(x, y)
        }

    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        if (event!!.action == MotionEvent.ACTION_DOWN) {
            init()
            invalidate()
        }
        return super.onTouchEvent(event)
    }
}

class BezierUtils(private var points: List<PointF>) {
    fun setPoints(points: List<PointF>) {
        this.points = points
    }

    /**
     * 德卡斯特利奥算法,计算贝塞尔曲线
     * @param i 贝塞尔曲线阶数
     * @param j 控制点
     * @param t 时间
     * @return
     */
    fun deCasteljauX(i: Int, j: Int, t: Float): Float {
        if (i == 1) {
            return (1 - t) * points[j].x + t * points[j + 1].x
        }
        return (1 - t) * deCasteljauX(i - 1, j, t) + t * deCasteljauX(i - 1, j + 1, t)
    }

    /**
     * 德卡斯特利奥算法,计算贝塞尔曲线
     * @param i 贝塞尔曲线阶数
     * @param j 控制点
     * @param t 时间
     * @return
     */
    fun deCasteljauY(i: Int, j: Int, t: Float): Float {
        if (i == 1) {
            return (1 - t) * points[j].y + t * points[j + 1].y
        }
        return (1 - t) * deCasteljauY(i - 1, j, t) + t * deCasteljauY(i - 1, j + 1, t)
    }
}
四阶贝塞尔曲线

相关文章

网友评论

      本文标题:贝塞尔曲线规则详解

      本文链接:https://www.haomeiwen.com/subject/xcivbctx.html