一次二次三次bezier曲线的计算方式及demo演示

前言

假如大家有看过最新的css3动画特性,相比对cube-bezier这个动画设置有印象,假如又有看过svg的path,那么想必对bezier曲线这个路径如何设置也会感兴趣。至于bezier的理论,本人在博客搬运了几篇,这篇文章主要用JavaScript脚本来计算bezier的各个位置,演示出来。

代码

<%--

--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>bezier曲线计算方式。</title>
  <script src="/static/lib/jquery-1.11.0.min.js"></script>
  <script src="/static/lib/jquery-migrate-1.2.1.js"></script>
</head>
<body>
<h3>一维贝塞尔曲线演示。</h3>

<div>请在400X400的范围内</div>
<div>请指定:起点:<input maxlength="4" value="0" id="linear_start_x">, <input maxlength="4" value="0" id="linear_start_y">  终点:<input maxlength="4" value="0" id="linear_end_x">,<input maxlength="4" value="0" id="linear_end_y"> </div>
<div><input type="button" value="开始演示路径填充" id="btn_linear"></div>
<div id="linear_debug"></div>
<div>
  <canvas width="400" height="400" id="canvas_linear"></canvas>
</div>

<h3>二次贝塞尔曲线演示。</h3>

<div>请在400X400的范围内</div>
<div>请指定:起点:<input maxlength="4" value="0" id="sqrt_start_x">, <input maxlength="4" value="0" id="sqrt_start_y">  终点:<input maxlength="4" value="0" id="sqrt_end_x">,<input maxlength="4" value="0" id="sqrt_end_y"> </div>
<div>控制点1:<input maxlength="4" value="0" id="sqrt_crt1_x">, <input maxlength="4" value="0" id="sqrt_crt1_y"></div>
<div><input type="button" value="开始演示路径填充" id="btn_sqrt"></div>
<div id="sqrt_debug"></div>
<div>
  <canvas width="400" height="400" id="canvas_sqrt"></canvas>
</div>


<h3>三次贝塞尔曲线演示。</h3>

<div>请在400X400的范围内</div>
<div>请指定:起点:<input maxlength="4" value="0" id="cube_start_x">, <input maxlength="4" value="0" id="cube_start_y">  终点:<input maxlength="4" value="0" id="cube_end_x">,<input maxlength="4" value="0" id="cube_end_y"> </div>
<div>控制点1:<input maxlength="4" value="0" id="cube_crt1_x">, <input maxlength="4" value="0" id="cube_crt1_y"></div>
<div>控制点2:<input maxlength="4" value="0" id="cube_crt2_x">, <input maxlength="4" value="0" id="cube_crt2_y"></div>
<div><input type="button" value="开始演示路径填充" id="btn_cube"></div>
<div id="cube_debug"></div>
<div>
  <canvas width="400" height="400" id="canvas_cube"></canvas>
</div>

<script type="text/javascript">
  //--线性bezier 曲线求值,根据t值来求值,t取值为[0,1],可以认为是0就在起点,1就在终点,是过程的百分比位置。
  var LinearBezier=function(point_start,point_end){
    var p_start={x:0,y:0};
    var p_end={x:0,y:0};
    p_start=point_start;
    p_end=point_end;
    //--计算t为某个值得时候的点。
    //--计算公式。
    /**
     *
     * [1 t]| 1   0| |P0|
     *      |-1   1| |P1|
     *
     * */
    this.getPoint=function(t){
      var _m_1_1=1-t;
      var _m_1_2= t;  //1*0+1*1+_t*0+_t*1;
      var _t_1_1= (1-t)*p_start.x+t*p_end.x; //0+(_t+1)*p_start.x+(_t+1)*p_end.x;
      var _t_1_2=(1-t)*p_start.y+t*p_end.y;   //0+(_t+1)*p_start.y+(_t+1)*p_end.y;
      var _res_point={
        x:_t_1_1
        ,y:_t_1_2
      };
      return _res_point;
    };
  };



  //--二次方bezier
  var SquareBezier=function(start_point,crt_point,end_point){
    var p_start={x:0,y:0};
    var p_end={x:0,y:0};
    p_start=start_point;
    p_end=end_point;
    var p_crt1=crt_point;
    /**
     * 计算公式:
     *            | 1  0  0|  |P0|
     * [1 t t*t ] |-2  2  0|  |P1|
     *            |1  -2  1|  |P2|
     * **/
    this.getPoint=function(t){
      var _matrix1=[1,t,t*t];
      var _matrix2=[
        [1,0,0]
        ,[-2,2,0]
        ,[1,-2,1]
      ];
      var _matrix3=[
            [p_start.x,p_start.y]
            ,[p_crt1.x,p_crt1.y]
            ,[p_end.x,p_end.y]
      ];
      var _matrix_tmp=[
        _matrix1[0]*_matrix2[0][0]+_matrix1[1]*_matrix2[1][0]+_matrix1[2]*_matrix2[2][0]
        ,_matrix1[0]*_matrix2[0][1]+_matrix1[1]*_matrix2[1][1]+_matrix1[2]*_matrix2[2][1]
        ,_matrix1[0]*_matrix2[0][2]+_matrix1[1]*_matrix2[1][2]+_matrix1[2]*_matrix2[2][2]
      ];
      var _matrix_final=[
              _matrix_tmp[0]*_matrix3[0][0]+_matrix_tmp[1]*_matrix3[1][0]+_matrix_tmp[2]*_matrix3[2][0]
              ,_matrix_tmp[0]*_matrix3[0][1]+_matrix_tmp[1]*_matrix3[1][1]+_matrix_tmp[2]*_matrix3[2][1]
      ];

      var _res_point={
        x:_matrix_final[0]
        ,y:_matrix_final[1]
      };
      return _res_point;
    };

  };//

  var CubeBezier=function(point_start,point1,point2,point_end){
    var p_start={x:0,y:0};
    var p_end={x:0,y:0};
    p_start=point_start;
    p_end=point_end;
    var p_crt1=point1;
    var p_crt2=point2;
    /**
     * 计算公式:
     *                  | 1  0  0   0|  |P0|
     * [1 t t*t  t*t*t] |-3  3  0   0|  |P1|
     *                  |3  -6  3   0|  |P2|
     *                  |-1  3  -3  1|  |p3|
     *
     * **/
    this.getPoint=function(t){
      var _matrix1=[1,t,t*t,t*t*t];
      var _matrix2=[
        [1,0,0,0]
        ,[-3,3,0,0]
        ,[3,-6,3,0]
        ,[-1,3,-3,1]
      ];

      var _matrix3=[
        [p_start.x,p_start.y]
        ,[p_crt1.x,p_crt1.y]
        ,[p_crt2.x,p_crt2.y]
        ,[p_end.x,p_end.y]
      ];
      var _matrix_tmp=[
        _matrix1[0]*_matrix2[0][0]+_matrix1[1]*_matrix2[1][0]+_matrix1[2]*_matrix2[2][0]+_matrix1[3]*_matrix2[3][0]
        ,_matrix1[0]*_matrix2[0][1]+_matrix1[1]*_matrix2[1][1]+_matrix1[2]*_matrix2[2][1]+_matrix1[3]*_matrix2[3][1]
        ,_matrix1[0]*_matrix2[0][2]+_matrix1[1]*_matrix2[1][2]+_matrix1[2]*_matrix2[2][2]+_matrix1[3]*_matrix2[3][2]
        ,_matrix1[0]*_matrix2[0][3]+_matrix1[1]*_matrix2[1][3]+_matrix1[2]*_matrix2[2][3]+_matrix1[3]*_matrix2[3][3]
      ];

      var _matrix_final=[
        _matrix_tmp[0]*_matrix3[0][0]+_matrix_tmp[1]*_matrix3[1][0]+_matrix_tmp[2]*_matrix3[2][0]+_matrix_tmp[3]*_matrix3[3][0]
        ,_matrix_tmp[0]*_matrix3[0][1]+_matrix_tmp[1]*_matrix3[1][1]+_matrix_tmp[2]*_matrix3[2][1]+_matrix_tmp[3]*_matrix3[3][1]
      ];

      var _res_point={
        x:_matrix_final[0]
        ,y:_matrix_final[1]
      };
      return _res_point;
    };


  };//
</script>
<script type="text/javascript">
  function DrawPoint(x,y,_context){
    var cans=_context;
    var cxt=_context;
    cxt.beginPath();
    cxt.arc(x,y,1,0,Math.PI*2,true);
    cxt.closePath();
    cxt.fill();
    return;
    //cans.moveTo(x,y);//第一个起点
    cans.lineTo(x,y);//第二个点
    //cans.lineTo(220,60);//第三个点(以第二个点为起点)
    cans.lineWidth=1;
    cans.strokeStyle = 'red';
    cans.stroke();
  }
</script>
<script type="text/javascript">
  //--演示程序。线性贝塞尔
  var linear_start_x=$("#linear_start_x");
  var linear_start_y=$("#linear_start_y");
  var linear_end_x=$("#linear_end_x");
  var linear_end_y=$("#linear_end_y");
  var canvas_linear=document.getElementById("canvas_linear");
  var context_linear=canvas_linear.getContext("2d");
  var btn_linear=$("#btn_linear");
  var linear_showing=false;
  var linear_debug=$("#linear_debug");

  btn_linear.click(function(){
    if(linear_showing==true){
      linear_debug.text("程序正在进行演示,请稍后再进行操作。");
      return;
    }
    linear_showing=true;
    context_linear.clearRect(0,0,canvas_linear.width,canvas_linear.height);
    //--绘制两个点。
    var _start_point={
      x:parseInt(linear_start_x.val())
      ,y:parseInt(linear_start_y.val())
    };
    var _end_point={
      x:linear_end_x.val()
      ,y:linear_end_y.val()

    };
    DrawPoint(_start_point.x,_start_point.y,context_linear);

    DrawPoint(_end_point.x,_end_point.y,context_linear);

    var _bezier=new LinearBezier(_start_point,_end_point);
    function linearDraw(t){
      var _t_point=_bezier.getPoint(t);
      console.log(_t_point);
      DrawPoint(_t_point.x,_t_point.y,context_linear);
    }

    var _now_t=0.01;

    var _interval1=setInterval(function(){

      if(_now_t>=1){
        clearInterval(_interval1);

        console.log("演示结束");
        linear_showing=false;
        return;
      }
      linearDraw(_now_t);
      _now_t=_now_t+0.01;
    },100);
  });
</script>

<script type="text/javascript">
  //--演示程序。二维贝塞尔
  var sqrt_start_x=$("#sqrt_start_x");
  var sqrt_start_y=$("#sqrt_start_y");
  var sqrt_end_x=$("#sqrt_end_x");
  var sqrt_end_y=$("#sqrt_end_y");
  var sqrt_crt1_x=$("#sqrt_crt1_x");
  var sqrt_crt1_y=$("#sqrt_crt1_y");
  var canvas_sqrt=document.getElementById("canvas_sqrt");
  var context_sqrt=canvas_sqrt.getContext("2d");
  var btn_sqrt=$("#btn_sqrt");
  var sqrt_showing=false;
  var sqrt_debug=$("#sqrt_debug");

  btn_sqrt.click(function(){
    if(sqrt_showing==true){
      sqrt_debug.text("程序正在进行演示,请稍后再进行操作。");
      return;
    }
    sqrt_showing=true;
    context_sqrt.clearRect(0,0,canvas_sqrt.width,canvas_sqrt.height);
    //--绘制两个点。
    var _start_point={
      x:parseInt(sqrt_start_x.val())
      ,y:parseInt(sqrt_start_y.val())
    };
    var _end_point={
      x:parseInt(sqrt_end_x.val())
      ,y:parseInt(sqrt_end_y.val())

    };
    var _crt_point1={
      x:parseInt(sqrt_crt1_x.val())
      ,y:parseInt(sqrt_crt1_y.val())
    };
    DrawPoint(_start_point.x,_start_point.y,context_sqrt);

    DrawPoint(_end_point.x,_end_point.y,context_sqrt);
    DrawPoint(_crt_point1.x,_crt_point1.y,context_sqrt);

    var _bezier=new SquareBezier(_start_point,_crt_point1,_end_point);
    function sqrtDraw(t){
      var _t_point=_bezier.getPoint(t);
      console.log(_t_point);
      DrawPoint(_t_point.x,_t_point.y,context_sqrt);
    }

    var _now_t=0.01;

    var _interval1=setInterval(function(){

      if(_now_t>=1){
        clearInterval(_interval1);
        console.log("演示结束");
        sqrt_showing=false;
        return;
      }
      sqrtDraw(_now_t);
      _now_t=_now_t+0.01;
    },100);
  });
</script>

<script type="text/javascript">
  //--演示程序。三次贝塞尔
  var cube_start_x=$("#cube_start_x");
  var cube_start_y=$("#cube_start_y");
  var cube_end_x=$("#cube_end_x");
  var cube_end_y=$("#cube_end_y");
  var cube_crt1_x=$("#cube_crt1_x");
  var cube_crt1_y=$("#cube_crt1_y");
  var cube_crt2_x=$("#cube_crt2_x");
  var cube_crt2_y=$("#cube_crt2_y");
  var canvas_cube=document.getElementById("canvas_cube");
  var context_cube=canvas_cube.getContext("2d");
  var btn_cube=$("#btn_cube");
  var cube_showing=false;
  var cube_debug=$("#cube_debug");

  btn_cube.click(function(){
    if(cube_showing==true){
      cube_debug.text("程序正在进行演示,请稍后再进行操作。");
      return;
    }
    cube_showing=true;
    context_cube.clearRect(0,0,canvas_cube.width,canvas_cube.height);
    //--绘制两个点。
    var _start_point={
      x:parseInt(cube_start_x.val())
      ,y:parseInt(cube_start_y.val())
    };
    var _end_point={
      x:parseInt(cube_end_x.val())
      ,y:parseInt(cube_end_y.val())

    };
    var _crt_point1={
      x:parseInt(cube_crt1_x.val())
      ,y:parseInt(cube_crt1_y.val())
    };
    var _crt_point2={
      x:parseInt(cube_crt2_x.val())
      ,y:parseInt(cube_crt2_y.val())
    };
    DrawPoint(_start_point.x,_start_point.y,context_cube);

    DrawPoint(_end_point.x,_end_point.y,context_cube);
    DrawPoint(_crt_point1.x,_crt_point1.y,context_cube);

    DrawPoint(_crt_point2.x,_crt_point2.y,context_cube);

    var _bezier=new CubeBezier(_start_point,_crt_point1,_crt_point2,_end_point);
    function cubeDraw(t){
      var _t_point=_bezier.getPoint(t);
      console.log(_t_point);
      DrawPoint(_t_point.x,_t_point.y,context_cube);
    }

    var _now_t=0.01;

    var _interval1=setInterval(function(){

      if(_now_t>=1){
        clearInterval(_interval1);
        console.log("演示结束");
        cube_showing=false;
        return;
      }
      cubeDraw(_now_t);
      _now_t=_now_t+0.01;
    },100);
  });
</script>
</body>
</html>

演示

线性演示
这里写图片描述

二次演示
这里写图片描述
三次演示
这里写图片描述

完毕。后续文章将介绍一些使用bezier曲线的地方。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
从2阶到7阶的贝赛尔曲线 private static final int MAX_COUNT = 7; // 贝塞尔曲线最大阶数 private static final int REGION_WIDTH = 30; // 合法区域宽度 private static final int FINGER_RECT_SIZE = 60; // 矩形尺寸 private static final int BEZIER_WIDTH = 10; // 贝塞尔曲线线宽 private static final int TANGENT_WIDTH = 6; // 切线线宽 private static final int CONTROL_WIDTH = 12; // 控制点连线线宽 private static final int CONTROL_RADIUS = 12; // 控制点半径 private static final int TEXT_SIZE = 40; // 文字画笔尺寸 private static final int TEXT_HEIGHT = 60; // 文本高度 private static final int RATE = 10; // 移动速率 private static final int HANDLER_WHAT = 100; private static final int FRAME = 1000; // 1000帧 private static final String[] TANGENT_COLORS = {"#7fff00", "#7a67ee", "#ee82ee", "#ffd700", "#1c86ee", "#8b8b00"}; // 切线颜色 private static final int STATE_READY = 0x0001; private static final int STATE_RUNNING = 0x0002; private static final int STATE_STOP = 0x0004; private static final int STATE_TOUCH = 0x0010; private Path mBezierPath = null; // 贝塞尔曲线路径 private Paint mBezierPaint = null; // 贝塞尔曲线画笔 private Paint mMovingPaint = null; // 移动点画笔 private Paint mControlPaint = null; // 控制点画笔 private Paint mTangentPaint = null; // 切线画笔 private Paint mLinePaint = null; // 固定线画笔 private Paint mTextPointPaint = null; // 点画笔 private Paint mTextPaint = null; // 文字画笔 private ArrayList mBezierPoints = null; // 贝塞尔曲线点集 private PointF mBezierPoint = null; // 贝塞尔曲线移动点 private ArrayList mControlPoints = null; // 控制点集 private ArrayList<ArrayList<ArrayList>> mTangentPoints; // 切线点集 private ArrayList<ArrayList> mInstantTangentPoints; private int mR = 0; // 移动速率 private int mRate = RATE; // 速率 private int mState; // 状态 private boolean mLoop = false; // 设置是否循环 private boolean mTangent = true; // 设置是否显示切线 private int mWidth = 0, mHe
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值