php 贝瑟尔曲线,canvas实现高阶贝塞尔曲线

本文主要介绍了canvas实现高阶贝塞尔曲线(N阶贝塞尔曲线生成器),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望能帮助到大家。

写在最前

由于原生的Canvas最高只支持到三阶贝塞尔曲线,那么我想添加多个控制点怎么办呢?(即便大部分复杂曲线都可以用3阶贝塞尔来模拟)与此同时,关于贝塞尔控制点的位置我们很难非常直观的清楚到底将控制点设置为多少可以形成我们想要的曲线。本着解决以上两个痛点同时社区内好像并没有N阶的解决方案(js版)故这次作者非常认真的开源了bezierMaker.js!

bezierMaker.js理论上支持N阶贝塞尔曲线的生成,同时提供了试验场供开发者可以自行添加并拖拽控制点最终生成一组绘制动画。非常直观的让开发者知道不同位置的控制点所对应的不同生成曲线。

如果你喜欢这个作品欢迎Star,毕竟star来之不易。。

项目地址:这里✨✨✨

为什么需要一个试验场?

在绘制复杂的高阶贝塞尔曲线时无法知道自己需要的曲线的控制点的精确位置。在试验场中进行模拟,可以实时得到控制点的坐标值,将得到的点坐标变为对象数组传递进BezierMaker类就可以生成目标曲线

效果图

0deb7a392d2d65f09285b6bc5e68e4a9.gif

67dd318136352b58a0e64c62ccd7ee39.gif

功能[x] 试验场可添加任意数量控制点

[x] 试验场支持展示曲线绘制的形成动画

[x] 控制点可自由拖拽

[x] 支持显示贝塞尔曲线形成过程的切线

[x] 3阶及以下贝塞尔曲线的绘制采用原生API

引入

绘制

上面的效果图为试验场的使用,当你通过试验场获得控制点的准确坐标之后,就可以调用bezierMaker.js进行曲线的直接绘制。

/**

* canvas canvas的dom对象

* bezierCtrlNodesArr 控制点数组,包含x,y坐标

* color 曲线颜色

*/

var canvas = document.getElementById('canvas')

//3阶之前采用原生方法实现

var arr0 = [{x:70,y:25},{x:24,y:51}]

var arr1 = [{x:233,y:225},{x:170,y:279},{x:240,y:51}]

var arr2 = [{x:23,y:225},{x:70,y:79},{x:40,y:51},{x:300, y:44}]

var arr3 = [{x:333,y:15},{x:70,y:79},{x:40,y:551},{x:170,y:279},{x:17,y:239}]

var arr4 = [{x:53,y:85},{x:170,y:279},{x:240,y:551},{x:70,y:79},{x:40,y:551},{x:170,y:279}]

var bezier0 = new BezierMaker(canvas, arr0, 'black')

var bezier1 = new BezierMaker(canvas, arr1, 'red')

var bezier2 = new BezierMaker(canvas, arr2, 'blue')

var bezier3 = new BezierMaker(canvas, arr3, 'yellow')

var bezier4 = new BezierMaker(canvas, arr4, 'green')

bezier0.drawBezier()

bezier1.drawBezier()

bezier2.drawBezier()

bezier3.drawBezier()

bezier4.drawBezier()

绘制结果

2284c2fc456cba5c14bcbe9fc28fe376.png

当控制点少于3个时,会适配使用原生的API接口。当控制点多于2个后,由我们自己实现的函数进行描点绘制。

核心原理

绘制贝塞尔曲线

绘制贝塞尔曲线的核心点在于贝塞尔公式的运用:

b7344cd4a9b653b03a4347fd8ab22b02.png

这个公式中的P0-Pn代表了从起点到各个控制点再到终点的各点与占比t的各种幂运算。

BezierMaker.prototype.bezier = function(t) { //贝塞尔公式调用

var x = 0,

y = 0,

bezierCtrlNodesArr = this.bezierCtrlNodesArr,

//控制点数组

n = bezierCtrlNodesArr.length - 1,

self = this

bezierCtrlNodesArr.forEach(function(item, index) {

if(!index) {

x += item.x * Math.pow(( 1 - t ), n - index) * Math.pow(t, index)

y += item.y * Math.pow(( 1 - t ), n - index) * Math.pow(t, index)

} else {

//factorial为阶乘函数

x += self.factorial(n) / self.factorial(index) / self.factorial(n - index) * item.x * Math.pow(( 1 - t ), n - index) * Math.pow(t, index)

y += self.factorial(n) / self.factorial(index) / self.factorial(n - index) * item.y * Math.pow(( 1 - t ), n - index) * Math.pow(t, index)

}

})

return {

x: x,

y: y

}

}

对所有点进行遍历同时根据当前占比t的值(0<=t<=1),计算出当前在贝塞尔曲线上的点坐标x,y。t的取值作者分成了1000份,即每次运算t+=0.01。此时算出的x,y即所求的贝塞尔曲线分成了1000份之后的某一点。当t值从0~1遍历1000次后生成1000个x,y对应坐标,依次描点画线即可模拟出高阶贝塞尔曲线。

对于贝塞尔公式的推导作者会在之后的文章中专门说明,现在你只需要知道我们通过贝塞尔公式计算出实际贝塞尔曲线被等分成了1000份的各点,用直线连接各点后即可模拟出类曲线。

对于模拟场贝塞尔曲线生成动画的实现

这个部分相关代码可以参考这里

整体思路是用递归的方式来将每个一层控制点当做1阶贝塞尔函数来计算下一层控制点并对应连线。具体逻辑作者会留到深入讲解贝塞尔曲线公式原理的时候一起梳理一下试验场的动画生成原理~

相关推荐:

以下是用Java实现八皇后问题的代码: ```java public class EightQueens { private static final int BOARD_SIZE = 8; private int[] queens; public EightQueens() { queens = new int[BOARD_SIZE]; } public void solve() { placeQueen(0); } private void placeQueen(int row) { if (row == BOARD_SIZE) { printQueens(); return; } for (int col = 0; col < BOARD_SIZE; col++) { if (isValid(row, col)) { queens[row] = col; placeQueen(row + 1); } } } private boolean isValid(int row, int col) { for (int i = 0; i < row; i++) { int otherCol = queens[i]; if (col == otherCol) { return false; } int colDiff = Math.abs(col - otherCol); int rowDiff = row - i; if (colDiff == rowDiff) { return false; } } return true; } private void printQueens() { System.out.println("======================="); for (int row = 0; row < BOARD_SIZE; row++) { for (int col = 0; col < BOARD_SIZE; col++) { if (queens[row] == col) { System.out.print("Q "); } else { System.out.print(". "); } } System.out.println(); } System.out.println("======================="); } public static void main(String[] args) { EightQueens solver = new EightQueens(); solver.solve(); } } ``` 在这个实现中,我们使用了一个一维数组来表示每一行皇后的位置,数组的下标表示行号,数组的表示列号。在递归过程中,我们依次尝试在每一行放置皇后,如果当前位置合法,则继续尝试下一行;如果当前位置不合法,则回溯到上一行重新尝试。在回溯算法的框架下,我们可以很容易地实现八皇后问题的求解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值