网站地图    收藏   

主页 > 前端 > js几何数学知识 >

js贝塞尔曲线公式代码

来源:未知    时间:2023-02-13 16:57 作者:小飞侠 阅读:

[导读] 今天带来JS贝塞尔曲线公式代码。 贝塞尔又称贝塞尔曲线,是为了解决计算机中特殊曲线而诞生的。根据数学公式我们先看下1阶,2阶,3阶贝塞尔曲线公式,对应如下图: 1阶贝塞尔 又...

今天带来JS贝塞尔曲线公式代码。


贝塞尔又称贝塞尔曲线,是为了解决计算机中特殊曲线而诞生的。根据数学公式我们先看下1阶,2阶,3阶贝塞尔曲线公式,对应如下图:

image.png


1阶贝塞尔

又称线性公式,是由2个点组成的,给定点P0、P1,线性贝兹曲线只是一条两点之间的直线。这条线由下式给出:

$B(t) = P0 + \left( p1 - p0 \right) * t = \left( 1-t \right) * P0 + t * P1, t \in [0,1]$

根据数学公式得出JS代码:

            //  一次贝塞尔
            function oneBsl() {
                //t
                var t = 0;

                // 初始参数
                var p0 = {
                    x: 200, y: 300
                };
                var p1 = {
                    x: 300, y: 200
                }
                
                var timer = setInterval(function(){
                    toDraw();
                },1000/60)


                function toDraw() {
                   t += 0.01;

                   if(t >= 1) {
                     clearInterval(timer)
                   }

                   var nowX = (1-t)*p0.x + t * p1.x;
                   var nowY = (1-t)*p0.y + t * p1.y;
                    
                    testNode.style.left = nowX + 'px';
                    testNode.style.top = nowY + "px";
                    
                    var boxNode = document.createElement("div");
                    boxNode.classList.add("box");
                    boxNode.style.left=testNode.offsetLeft+"px";
                    boxNode.style.top=testNode.offsetTop+"px";
                    document.body.appendChild(boxNode);


                }
            }

            oneBsl();

2阶贝塞尔

二次方贝兹曲线的路径由给定点P0、P1、P2的函数B(t)追踪:

$B(t) = \left( 1-t \right)^{2}P0 + 2t\left( 1-t \right)P1 + t^{2}P2, t \in [0,1]$

根据数学公式得出JS代码:

             //  二次贝塞尔
            function twoBsl() {
                //t
                var t = 0;

                // 初始参数
                var p0 = {
                    x: 500, y: 300
                };
                var p1 = {
                    x: 700, y: 150
                }
                var p2 = {
                    x: 900, y: 300
                }
                
                var timer = setInterval(function(){
                    toDraw();
                },1000/60)


                function toDraw() {
                   t += 0.01;

                   if(t >= 1) {
                     clearInterval(timer)
                   }

                   var nowX = Math.pow((1-t), 2) * p0.x + 2 * t * (1 - t) * p1.x + Math.pow((t), 2) * p2.x;
                   var nowY = Math.pow((1-t), 2) * p0.y + 2 * t * (1 - t) * p1.y + Math.pow((t), 2) * p2.y;
                    
                    testNode.style.left = nowX + 'px';
                    testNode.style.top = nowY + "px";
                    
                    var boxNode = document.createElement("div");
                    boxNode.classList.add("box");
                    boxNode.style.left=testNode.offsetLeft+"px";
                    boxNode.style.top=testNode.offsetTop+"px";
                    document.body.appendChild(boxNode);


                }
            }

            twoBsl();


3阶贝塞尔曲线

P0、P1、P2、P3四个点在平面或在三维空间中定义了三次方贝兹曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1或P2;这两个点只是在那里提供方向资讯。P0和P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。

曲线的参数形式为:

image.png

根据数学公式得出JS代码:

             //  三次贝塞尔
            function threeBsl() {
                //t
                var t = 0;

                // 初始参数
                var p0 = {
                    x: 500, y: 600
                };
                var p1 = {
                    x: 700, y: 350
                }
                var p2 = {
                    x: 900, y: 350
                }
                var p3 = {
                    x: 900, y: 600
                }
                
                var timer = setInterval(function(){
                    toDraw();
                },1000/60)



                function getYh() {
                    var yhArr = [];  
                    var n = 4;  
              
                    for(i=0; i < n; i++) {  
                        if (typeof yhArr[i] === 'undefined') {  
                         yhArr[i] = []; // 初始化二维  
                        }  
                        var secondN = i + 1; // 二行长度  
                        // 遍历二行  
                        for(j=0; j<secondN; j++) {  
              
                            // 当前值  
                            var nowNum = 1;  
              
                            // 校验父级前后存在并相加  
                            if (yhArr[i - 1] && yhArr[i - 1][j-1] && yhArr[i - 1][j]) {  
                                nowNum = yhArr[i - 1][j-1] + yhArr[i - 1][j];  
                            }  
              
                            yhArr[i][j] = nowNum;  
                        }  
                    }  
                    console.log(yhArr)  
                    return yhArr;
                }


                function toDraw(cf) {
                   t += 0.01;

                   if(t >= 1) {
                     clearInterval(timer)
                   }

                   var nowX = Math.pow((1-t), 3) * p0.x   +  (3 * p1.x * t * Math.pow((1-t), 2))  + (3 * p2.x *  Math.pow((t), 2)) * (1-t)  + p3.x *Math.pow((t), 3);
                   var nowY = Math.pow((1-t), 3) * p0.y   +  (3 * p1.y * t * Math.pow((1-t), 2))  + (3 * p2.y *  Math.pow((t), 2)) * (1-t)  + p3.y *Math.pow((t), 3);
                    
                    testNode.style.left = nowX + 'px';
                    testNode.style.top = nowY + "px";
                    
                    var boxNode = document.createElement("div");
                    boxNode.classList.add("box");
                    boxNode.style.left=testNode.offsetLeft+"px";
                    boxNode.style.top=testNode.offsetTop+"px";
                    document.body.appendChild(boxNode);


                }
            }

            threeBsl();


n阶贝塞尔曲线:

image.png

根据多阶的规律,可以得出如下结果:

a * (1 - t)^b * t^c * Pn;

其中:

  • b: (N - 1) 递减到 0 (b 为 1-t 的幂)

  • c: 0 递增到 (N - 1) (c 为 t 的幂)

  • a: 在 N 分别为 1,2,3,4,5 时将其值用如下形式表示:

其中:

a 则可以用杨辉三角表达,杨慧三角可以看我上一篇文章 https://www.zixuephp.com/wzqd/jsjiheshuxuezhishi/20230208_46004.html

具体思路如下:

构造杨辉三角二维数组,然后遍历得a,分别带入 b , c 的关系到公式中,对所有结果累加即可。

多阶公式效果预览:

多阶公式JS代码:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>贝塞尔canvas</title>
	<style type="text/css">
		*{
			margin: 0px;
			padding: 0px;
		}
	</style>
</head>
<body>
	<canvas id="canvas" width="400" height="400"></canvas>
	<script type="text/javascript">

	var t = 0; // 初始化t
	// 初始化控制点
	var points = [
			{
              x: 10, y: 100
            },
			{
               x: 100, y: 300
            },
            {
               x: 150, y: 350
            },
            {
               x: 200, y: 120
            },
            {
               x: 300, y: 350
            },
            {
               x: 350, y: 100
            }

		];

        function getYh(ponts) {
            var yhArr = [];  
            var n = ponts.length;  
      
            for(i=0; i < n; i++) {  
                if (typeof yhArr[i] === 'undefined') {  
                 yhArr[i] = []; // 初始化二维  
                }  
                var secondN = i + 1; // 二行长度  
                // 遍历二行  
                for(j=0; j<secondN; j++) {  
      
                    // 当前值  
                    var nowNum = 1;  
      
                    // 校验父级前后存在并相加  
                    if (yhArr[i - 1] && yhArr[i - 1][j-1] && yhArr[i - 1][j]) {  
                        nowNum = yhArr[i - 1][j-1] + yhArr[i - 1][j];  
                    }  
      
                    yhArr[i][j] = nowNum;  
                }  
            }  
            console.log(yhArr[n-1])  
            return yhArr[n-1];
        }

        // n次贝塞尔
        function nBsl() { 
        	//  获得当a组
        	var as = getYh(points);
        	t += 0.01;
           if(t >= 1) {
             clearInterval(timer)
           }

           var tempX = 0;
           var tempY = 0;
           // N 为控制点数量
           for(var i=0; i<as.length;i++) {
           	var a = as[i];
           	var b = as.length - (i+1); // (N - 1) 递减到 0 (b 为 1-t 的幂)
           	var c = i; // 0 递增到 (N - 1) (c 为 t 的幂)
           	tempX +=  getTemp(a, b, c, points[i].x);
           	tempY +=  getTemp(a, b, c, points[i].y);

           	// 绘制控制点
           	draw(points[i].x, points[i].y, 'red', 5);

           }

           function getTemp(a, b, c, Pn) {
				var _temp = a * Math.pow(1 - t, b) * Math.pow(t, c) * Pn;
				return _temp;
           }

           draw(tempX, tempY);

           console.log('tempX',tempX, 'tempY', tempY)
        }

        // 绘制
        function draw(x, y, color, w) {
        	var canvas = document.querySelector("#canvas");
        	var context = canvas.getContext("2d");
        	var w = w ? w : 1;

        	context.beginPath();  
			context.strokeStyle = color ? color : 'black';
			// context.moveTo(x, y);  
        	// context.lineTo(x, y);  
        	context.rect(x, y, w, w);  
        	context.stroke();  
        }


        
        var timer = setInterval(function(){
            nBsl();
        },1000/60)


		
	</script>
</body>
</html>


以上就是js贝塞尔曲线公式代码全部内容,感谢大家支持自学php网。

自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习

京ICP备14009008号-1@版权所有www.zixuephp.com

网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com

添加评论