贝塞尔曲线N阶实现-德卡斯特里奥算法(De Casteljau’s Algorithm)
贝塞尔曲线很多客户端已经自行集成,安卓ios或是web,今天基于算法动手实现一次,今天只放源码,暂时不做说明了(还要加班,--~),源码在下面,直接看也能看懂
德卡斯特里奥算法的基础就是在向量AB上选择一个点C,使得C分向量AB为u:1-u(也就是∣AC∣:∣AB∣= u)。给定点A、B的坐标以及u(u∈[0,1])的值,点C的坐标便为:C = A + (B - A) * u = (1 - u) * A + B * u。
我本来是做安卓的,不过安卓调试太慢了,我就用html实现了下 复制代码直接到txt改后缀html就可以看到效果了,其他语言和逻辑可以通用
<!DOCTYPE HTML>
<html>
<body>
<canvas id="BddCanvas" width="1000" height="500" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
贝塞尔曲线N阶算法演示
<script type="text/javascript">
<!-- 拿到画布 -->
var c=document.getElementById("BddCanvas")
<!-- 拿到绘制环境 -->
var canvasRC2D=c.getContext("2d")
<!-- 测试4个控制点 -->
var points_control=new Array(
{x:10,y:10},
{x:150,y:400},
{x:300,y:40},
{x:800,y:300})
<!-- 先展示折线效果 -->
canvasRC2D.moveTo(points_control[0].x,points_control[0].y)
canvasRC2D.lineTo(points_control[1].x,points_control[1].y)
canvasRC2D.lineTo(points_control[2].x,points_control[2].y)
canvasRC2D.lineTo(points_control[3].x,points_control[3].y)
<!-- 系统自带实现三阶贝塞尔的效果 -->
canvasRC2D.moveTo(points_control[0].x,points_control[0].y)
canvasRC2D.bezierCurveTo(
points_control[1].x,points_control[1].y,
points_control[2].x,points_control[2].y,
points_control[3].x,points_control[3].y
)
canvasRC2D.stroke()
//自己按原理算法实现
<!-- //AB两点间符合要求的c 取向量 算法基础∣AC∣:∣AB∣= u (u∈[0,1]) C = A + (B - A) * u = (1 - u) * A + B * u -->
//重新开始一条路径 采用红色和往下一点的起点+40作为区分
canvasRC2D.beginPath()
canvasRC2D.strokeStyle="red"
canvasRC2D.lineWidth=3
points_control=new Array(
{x:10,y:10+40},
{x:150,y:400+40},
{x:300,y:40+40},
{x:800,y:300+40})
var x_start = points_control[0].x
var y_start = points_control[0].y
canvasRC2D.moveTo(x_start,y_start)
//动态比例 越小曲线越细腻u = 0.01
var time = 0
for (var u=0;u<=1;u+=0.01){
for (var i=1;i<points_control.length;++i){
for (var j=0;j<points_control.length-i;j++){
console.log("time:"+time++);
if(i == 1){
<!-- //根据上面公式 -->
points_control[j].x = parseInt((1 - u) * points_control[j].x + points_control[j + 1].x * u)
points_control[j].y = parseInt((1 - u) * points_control[j].y + points_control[j + 1].y * u)
continue
}
<!-- //i != 1时,通过上一次迭代的结果计算 -->
points_control[j].x = points_control[j].x * (1 - u) + points_control[j + 1].x * u
points_control[j].y = points_control[j].y * (1 - u) + points_control[j + 1].y * u
}
console.log("计算结果:x"+x_start);
//绘制线条
//canvasRC2D.moveTo(x_start,y_start)
canvasRC2D.lineTo(points_control[0].x,points_control[0].y)
//生成一个新点
x_start = points_control[0].x
y_start = points_control[0].y
canvasRC2D.stroke()
}
}
<!-- //用延时展现绘制过程和外层循坏 多阶展现-->
points_control=new Array(
{x:10,y:10+80},
{x:150,y:400+80},
{x:300,y:40+80},
{x:800,y:300+80},
{x:20,y:331},
{x:80,y:80},
{x:500,y:150},
{x:31,y:66},
{x:400,y:1},
{x:31,y:30},
{x:800,y:2},
{x:400,y:500},
{x:1000,y:1})
x_start = points_control[0].x
y_start = points_control[0].y
canvasRC2D.beginPath()
canvasRC2D.strokeStyle="green"
canvasRC2D.lineWidth=3
canvasRC2D.moveTo(x_start,y_start)
<!-- for (var i=0;i<points_control.length;i++){ -->
<!-- canvasRC2D.lineTo(points_control[i].x,points_control[i].y) -->
<!-- } -->
<!-- canvasRC2D.moveTo(x_start,y_start) -->
u=0
var interval=self.setInterval("clock()",30)
function clock() {
for (var i=1;i<points_control.length;++i){
for (var j=0;j<points_control.length-i;j++){
if(i == 1){
<!-- //根据上面公式 -->
points_control[j].x = parseInt((1 - u) * points_control[j].x + points_control[j + 1].x * u)
points_control[j].y = parseInt((1 - u) * points_control[j].y + points_control[j + 1].y * u)
continue
}
<!-- //i != 1时,通过上一次迭代的结果计算 -->
points_control[j].x = points_control[j].x * (1 - u) + points_control[j + 1].x * u
points_control[j].y = points_control[j].y * (1 - u) + points_control[j + 1].y * u
}
//绘制线条
//canvasRC2D.moveTo(x_start,y_start)
canvasRC2D.lineTo(points_control[0].x,points_control[0].y)
//生成一个新点
x_start = points_control[0].x
y_start = points_control[0].y
canvasRC2D.stroke()
u+=0.001
if(u>=1){
clearInterval(interval)
}
}
}
</script>
</body>
</html>