精华内容
下载资源
问答
  • 这是用Processing实现的二阶贝塞尔曲线演示动画。 PVector p0, p1, p2; float t; PVector p00, p11; PVector p02; void setup() { size(400, 400); p0 = new PVector(100, 300); p1 = new PVe

    原理

    这篇文章讲的很清楚:贝塞尔曲线原理(简单阐述)

    演示

    在这里插入图片描述
    以下演示转自 贝塞尔曲线 总结

    一阶:

    在这里插入图片描述
    二阶:

    在这里插入图片描述

    三阶:

    在这里插入图片描述

    四阶:

    在这里插入图片描述

    五阶:

    在这里插入图片描述

    代码

    这是用Processing实现的二阶贝塞尔曲线演示动画。

    PVector p0, p1, p2;
    float t;
    PVector p00, p11;
    PVector p02;
    
    void setup() {
      size(400, 400);
      p0 = new PVector(100, 300);
      p1 = new PVector(200, 100);
      p2 = new PVector(300, 250);
      t = 0.001;
    }
    
    void draw() {
      background(200); 
      
      update();
      
      showPoints();
      showCurves();
      showText();
    }
    
    void mousePressed() {
      t = 0.001;
    }
    
    void update() {
      if(t < 0.999){
         t += 0.005; 
      }
      p00 = new PVector((1-t)*p0.x + t*p1.x, (1-t)*p0.y + t*p1.y);
      p11 = new PVector((1-t)*p1.x + t*p2.x, (1-t)*p1.y + t*p2.y);
      p02 = new PVector((1-t)*p00.x + t*p11.x, (1-t)*p00.y + t*p11.y);
    }
    
    void showPoints() {
      push();
      
      stroke(30);
      strokeWeight(6);
      point(p0.x, p0.y);
      point(p1.x, p1.y);
      point(p2.x, p2.y);
      
      stroke(0, 200, 0);
      strokeWeight(8);
      point(p00.x, p00.y);
      point(p11.x, p11.y);
      
      stroke(200, 0, 0);
      point(p02.x, p02.y);
      
      pop();
    }
    
    void showCurves() {
      push();
      
      stroke(0);
      strokeWeight(1);
      noFill();
      
      beginShape();
      vertex(p0.x, p0.y);
      quadraticVertex(p1.x, p1.y, p2.x, p2.y);
      endShape();
      
      line(p0.x, p0.y, p1.x, p1.y);
      line(p1.x, p1.y, p2.x, p2.y);
      
      push();
      stroke(0, 0, 200);
      line(p00.x, p00.y, p11.x, p11.y);
      pop();
      
      pop();
    }
    
    void showText() {
      push();
      
      fill(0);
      textSize(14);
      textAlign(RIGHT, TOP);
      text("P0", p0.x, p0.y);
      text("P1", p1.x, p1.y);
      text("P2", p2.x, p2.y);
      
      text("P00", p00.x, p00.y);
      text("P11", p11.x, p11.y);
      
      text("P02", p02.x, p02.y);
      pop();
    }
    
    

    参考

    贝塞尔曲线原理(简单阐述)
    贝塞尔曲线 总结

    展开全文
  • 二阶贝塞尔曲线

    千次阅读 2019-09-12 15:21:14
    实现二阶贝塞尔曲线须知三个点点坐标,起点P0(x,y), 控制点P1(x,y),终点P2(x,y) 示例: /** * 二阶贝塞尔曲线 */ public class BSE2View extends View { /*起点*/ int startPointX; int ...

    在这里插入图片描述
    实现原理

    实现二阶贝塞尔曲线须知三个点点坐标,起点P0(x,y), 控制点P1(x,y),终点P2(x,y)
    公式 B(t) = (1-t)2P0 + 2t(i-t)P1+t2P2
    在这里插入图片描述

    示例:

    /**
     * 二阶贝塞尔曲线
     */
    public class BSE2View extends View {
    
    
        /*起点*/
        int startPointX;
        int startPointY;
    
        /*控制点*/
        int conPointX ;
        int conPointY ;
    
        /*终点*/
        int endPiontX;
        int endPiontY;
    
        /*曲线*/
        Path path;
        /*画笔*/
        Paint paint;
    
    
    
        public BSE2View(Context context) {
            this(context,null);
        }
    
        public BSE2View(Context context,  AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public BSE2View(Context context,  AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initPaint();
        }
    
        private void initPaint() {
            path = new Path();
    
            paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            paint.setDither(true);
            paint.setAntiAlias(true);
            paint.setColor(getContext().getResources().getColor(R.color.colorPrimaryDark));
            paint.setStrokeWidth(10);
            paint.setStyle(Paint.Style.FILL_AND_STROKE);
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            // 开始点的坐标
            startPointX = 0;
            startPointY = 0;
            // 结束点的位置
            endPiontX = w ;
            endPiontY = 0;
            // 控制点坐标
            conPointX = w / 2;
            conPointY = 0;
    
        }
    
        float y = 0;
    
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    y = event.getRawY();
                case MotionEvent.ACTION_MOVE:
                    conPointX = (int) event.getRawX();
                    conPointY = (int) (event.getRawY()-y);
                    if (conPointY>0){
                        invalidate();
                    }
                break;
                case MotionEvent.ACTION_UP:
                    conPointX = endPiontX / 2;
                    conPointY = 0;
                    invalidate();
                    break;
            }
            return true;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            path.reset(); // 初始化Path
            path.moveTo(startPointX,startPointY);
            path.quadTo(conPointX,conPointY,endPiontX,endPiontY);
            canvas.drawPath(path,paint);
        }
    }
    
    
    展开全文
  • 今天在学习贝塞尔曲线的过程中觉得很新奇,特别是之前觉得很神秘的东西一下全部融会贯通了,为了实践,特地写了一个demo——波浪图,先看效果图:纸上得来终觉浅,绝知此事要躬行!... 二阶贝塞尔曲线形成原理
    今天在学习贝塞尔曲线的过程中觉得很新奇,特别是之前觉得很神秘的东西一下全部融会贯通了,为了实践,特地写了一个demo——波浪图,先看效果图:

    这里写图片描述

    纸上得来终觉浅,绝知此事要躬行!本来觉得挺简单的一件事结果各种坑!什么,你说贝塞尔曲线不简单?no,no,看看大神们是怎么总结的?

    二阶贝塞尔曲线形成原理:

    1.连接 A,B 形成 AB 线段,连接 B,C 形成 BC 线段。

    连成AB,BC线段

    2.在 AB 线段取一个点 D,BC 线段取一个点 E ,使其满足条件: AD/AB = BE/BC,连接 D,E 形成线段 DE。

    连接DE

    3.在 DE 取一个点 F,使其满足条件:AD/AB = BE/BC = DF/DE。

    这里写图片描述

    4.而满足这些条件的所有的F点所形成的轨迹就是二阶贝塞尔曲线,动态过程如下:

    这里写图片描述

    上面的代码解释得很清楚了,已知D,可以求得E,已知D、E可以求得F,如果D为一个变量,则F在二维平面就是一条曲线,如图四。

    那么知道了二阶贝塞尔曲线的原理以后,怎么运用呢?

    方法预览:

    public void quadTo (float x1, float y1, float x2, float y2)

    怎么用:

    因为二阶贝塞尔曲线需要三个点才能确定,所以quadTo方法中的四个参数分别是确定第二,第三的点的。第一个点就是path上次操作的点。
    现在用一个实例来练习下这个方法:

    水波纹效果:

    这里写图片描述

    实现思路:

    这里写图片描述

    我看见这幅图的第一思路是首先得到波浪长度mWL、波浪中心点mCenterY。因为图中的波浪宽度为整个屏幕宽度,所以我们需要得到屏幕的宽度。百度一下方法就出来了:

    方法一:

           //获取屏幕的宽度  
        public static int getScreenWidth(Context context) {  
            WindowManager manager = (WindowManager) context  
                    .getSystemService(Context.WINDOW_SERVICE);  
            Display display = manager.getDefaultDisplay();  
            return display.getWidth();  
        }  
        //获取屏幕的高度  
        public static int getScreenHeight(Context context) {  
            WindowManager manager = (WindowManager) context  
                    .getSystemService(Context.WINDOW_SERVICE);  
            Display display = manager.getDefaultDisplay();  
            return display.getHeight();  
        }  

    方法二:

    DisplayMetrics  dm = new DisplayMetrics();      
    
    getWindowManager().getDefaultDisplay().getMetrics(dm);      
    
    int screenWidth = dm.widthPixels;                
    
    int screenHeight = dm.heightPixels;    

    由于第二种方法只能在Activity里面使用,所以这里使用第一种方法。但是在写的过程中我又发现一个提醒:

    这里写图片描述

    有强迫症的我马上去官网查了一下,发现官网推荐的是另一个方法,于是马上就改用了另一个方法:

    这里写图片描述

    这里写图片描述

    于是,我们现在就可以根据波浪的宽度和中心点绘制一条静态的波浪线,代码如下:

     @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            mPath.reset();
            mPath.moveTo(-mWL, mCenterY); //将path操作的起点移动到(-mWL,mCenterY)
    
           mPath.quadTo((-mWL * 3 / 4) , mCenterY + 60, (-mWL / 2), mCenterY); //画出第一段波纹的第一条曲线
           mPath.quadTo((-mWL / 4) , mCenterY - 60, 0, mCenterY); //画出第一段波纹的第二条曲线
           mPath.quadTo((mWL /4) , mCenterY + 60, (mWL / 2), mCenterY); //画出第二段波纹的第一条曲线
           mPath.quadTo((mWL * 3/ 4) , mCenterY - 60, mWL, mCenterY);  //画出第二段波纹的第二条曲线
    
            mPath.lineTo(mScreenWidth, mScreenHeight);
            mPath.lineTo(0, mScreenHeight);
            mPath.close();
            canvas.drawPath(mPath,mPaint);
    
        }

    查看加载效果的时候发现一个坑,就是荣耀的真机显示绘制结果的时候左边居然有一条很宽的线,这个时候为了检查不是贝塞尔曲线的问题,我还在贝塞尔曲线X方向起点到终点绘制了一条直线,但是依然如此。

    这里写图片描述

    然后我用自己的小米5测试了一下,居然完全没有任何问题:

    这里写图片描述

    虽然后来发现是因为使用了ConstraintLayout布局,然后自定义控件左边距有8dp,然后给自定义控件写死了宽度,因此小米5的宽度刚刚合适,,,,,

    修改了以后正常了,于是继续将静态的波浪线调整成动态的波浪线。其实逻辑是很简单,就是给自定义View一个点击事件,然后在时间中启动一个属性动画,动态的修改波浪线水平方向右移的位置,全部代码写出来:

    
    
    
    /**
     * 自定义波浪图
     * Created by 魏兴 on 2017/6/12.
     */
    
    public class WaveView1 extends View implements View.OnClickListener{
    
        private static final String TAG = "WaveView";
        private Context mContext;
        /**
         * 波纹段长度
         */
        private int mWL;
        /**
         * 波浪高度中点
         */
        private float mCenterY;
        private float mScreenWidth;
        private float mScreenHeight;
        private int mOffset;
        private int mWaveCount;
        private Path mPath;
        private Paint mPaint;
    
    
        private Paint mCyclePaint;
    
    
        public WaveView1(Context context) {
            super(context);
            this.mContext = context;
    //        init();
        }
    
        public WaveView1(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            this.mContext = context;
    //        init();
        }
    
        public WaveView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            this.mContext = context;
    //        init();
        }
    
        private void init() {
            WindowManager manager = (WindowManager) mContext .getSystemService(Context.WINDOW_SERVICE);
            Display display = manager.getDefaultDisplay();
    
            Point po = new Point();
            display.getSize(po);
            mWL = po.x;
    
            mCyclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mCyclePaint.setColor(Color.RED);
            mCyclePaint.setStyle(Paint.Style.FILL_AND_STROKE);
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
    
            mPaint = new Paint();       // 创建画笔
            mPaint.setColor(Color.BLUE);  // 画笔颜色 - 黑色
            mPaint.setAntiAlias(true);
            mPaint.setStyle(Paint.Style.FILL_AND_STROKE);  // 填充模式 - 填充
    
            mPath = new Path();
    
            mWL = w*3/4;
    
            mCenterY = h/2f;
            mScreenHeight = h;
            mScreenWidth = w;
            //加1.5:至少保证波纹有2个,至少2个才能实现平移效果
            mWaveCount = (int) Math.round(mScreenWidth / mWL + 1.5);
    
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            mPath.reset();
            //移到屏幕外最左边
            mPath.moveTo(-mWL + mOffset, mCenterY);
    
            for (int i = 0; i < mWaveCount; i++) {
                //正弦曲线
                mPath.quadTo((-mWL * 3 / 4) + (i * mWL) + mOffset, mCenterY + 60, (-mWL / 2) + (i * mWL) + mOffset, mCenterY);
                mPath.quadTo((-mWL / 4) + (i * mWL) + mOffset, mCenterY - 60, i * mWL + mOffset, mCenterY);
                //测试红点
    //            canvas.drawCircle((-mWL * 3 / 4) + (i * mWL) + mOffset, mCenterY + 60, 5, mCyclePaint);
    //            canvas.drawCircle((-mWL / 2) + (i * mWL) + mOffset, mCenterY, 5, mCyclePaint);
    //            canvas.drawCircle((-mWL / 4) + (i * mWL) + mOffset, mCenterY - 60, 5, mCyclePaint);
    //            canvas.drawCircle(i * mWL + mOffset, mCenterY, 5, mCyclePaint);
            }
            //填充矩形
            mPath.lineTo(mScreenWidth, mScreenHeight);
            mPath.lineTo(0, mScreenHeight);
            mPath.close();
            canvas.drawPath(mPath, mPaint);
        }
    
        @Override
        public void onClick(View view) {
            try {
    
                ValueAnimator animator = ValueAnimator.ofInt(-mWL, mWL);
                animator.setDuration(1000);
                animator.setRepeatCount(ValueAnimator.INFINITE);
                animator.setInterpolator(new LinearInterpolator());
                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        mOffset = (int) animation.getAnimatedValue();
                        postInvalidate();
                    }
                });
                animator.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    
        }
    
    
    }
    

    然后在实例化控件以后调用Click方法(不能直接点击View,因为Click方法此处并没有响应,需要重写boolean onTouchEvent(MotionEvent event)方法来定义Click事件——我猜的哈,反正我直接点击的时候此处方法并没有响应)。于是我简单申明控件以后直接调用了Click方法。大坑出现了!

    这里写图片描述

    此处波浪图并没有动起来,而且属性方法里面打印的日志显示设置的ofint()方法参数(这个是成员变量,即波浪宽度)为900,偏移量为0。上网百度“属性动画失效”找不到资料,后来查了半天发现是因为Activity里面声明控件并调用了Click方法,这个时候宽度默认为0,因此属性动画的偏移量一直为0。
    于是修改调用代码:

    public class WaveActivity extends AppCompatActivity {
    
        private WaveView1 mWave;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_wave);
    
            mWave = (WaveView1) findViewById(R.id.waveView);
            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            mWave.onClick(null);
                        }
                    });
                }
            },500);
    
        }
    
    
    }
    

    续三阶贝塞尔曲线形成原理:

    1.连接 A,B 形成 AB 线段,连接 B,C 形成 BC 线段,连接 C,D 形成 CD 线段。

    这里写图片描述

    2.在AB线段取一个点 E,BC 线段取一个点 F,CD 线段取一个点 G,使其满足条件: AE/AB = BF/BE = CG/CD。连接 E,F 形成线段 EF,连接 F,G 形成线段 FG。

    这里写图片描述

    3.在EF线段取一个点 H,FG 线段取一个点 I,使其满足条件: AE/AB = BF/BE = CG/CD = EH/EF = FI/FG。连接 H,I 形成线段 HI。

    这里写图片描述

    4.在 HI 线段取一个点 J,使其满足条件: AE/AB = BF/BE = CG/CD = EH/EF = FI/FG = HJ/HI。

    这里写图片描述

    5.而满足这些条件的所有的J点所形成的轨迹就是三阶贝塞尔曲线,动态过程如下:

    这里写图片描述

    方法预览:
    public void quadTo (float x1, float y1, float x2, float y2)
    绘制圆形:
    这里写图片描述
    修改坐标:
    这里写图片描述
    最终效果:
    这里写图片描述

    最后再来一张效果图:

    这里写图片描述

    参考资料:

    Path从懵逼到精通(2)——贝塞尔曲线

    Android自定义View——贝塞尔曲线实现水波纹效果

    展开全文
  • P0为起点,Pn为终点,Pi为控制点一阶贝塞尔曲线(线段):一阶贝塞尔曲线公式一阶贝塞尔曲线演示意义:由 P0 至 P1 的连续点, 描述的一条线段二阶贝塞尔曲线(抛物线):二阶贝塞尔曲线公式二阶贝塞尔曲线演示原理:由 P0...

    5982e2322f3b

    贝塞尔曲线学习

    1.贝塞尔曲线

    以下公式中:

    B(t)为t时间下 点的坐标;

    P0为起点,Pn为终点,Pi为控制点

    一阶贝塞尔曲线(线段):

    5982e2322f3b

    一阶贝塞尔曲线公式

    5982e2322f3b

    一阶贝塞尔曲线演示

    意义:由 P0 至 P1 的连续点, 描述的一条线段

    二阶贝塞尔曲线(抛物线):

    5982e2322f3b

    二阶贝塞尔曲线公式

    5982e2322f3b

    二阶贝塞尔曲线演示

    原理:由 P0 至 P1 的连续点 Q0,描述一条线段。

    由 P1 至 P2 的连续点 Q1,描述一条线段。 由 Q0 至 Q1 的连续点 B(t),描述一条二次贝塞尔曲线。 经验:P1-P0为曲线在P0处的切线。

    三阶贝塞尔曲线:

    5982e2322f3b

    三阶贝塞尔曲线公式

    5982e2322f3b

    三阶贝塞尔曲线演示

    通用公式:

    5982e2322f3b

    通用贝塞尔曲线公式

    高阶贝塞尔曲线:

    4阶曲线:

    5982e2322f3b

    四阶贝塞尔曲线演示

    5阶曲线:

    5982e2322f3b

    五阶贝塞尔曲线演示

    1.1.生成贝塞尔曲线-迭代法

    下面我们用代码来生成贝塞尔曲线,来展示如何贝塞尔曲线的生成原理:

    package com.che.chechengwang.support.view.bezier;

    import android.animation.FloatEvaluator;

    import android.animation.ValueAnimator;

    import android.content.Context;

    import android.graphics.Canvas;

    import android.graphics.Color;

    import android.graphics.Paint;

    import android.graphics.Path;

    import android.graphics.PointF;

    import android.util.AttributeSet;

    import android.view.View;

    import android.view.animation.LinearInterpolator;

    import java.util.ArrayList;

    import java.util.HashMap;

    import java.util.List;

    import java.util.Map;

    import java.util.Random;

    /**

    * 生成贝塞尔曲线-迭代法

    *

    * 作者:余天然 on 16/6/14 下午2:10

    */

    public class BezierGenerater1 extends View {

    private Paint paint;

    private int centerX, centerY;

    private List points;

    private FloatEvaluator evaluator;

    private float fraction;

    private Map colors;

    private List destPoints;

    public BezierGenerater1(Context context, AttributeSet attrs) {

    super(context, attrs);

    init();

    }

    private void init() {

    paint = new Paint();

    paint.setAntiAlias(true);

    paint.setStyle(Paint.Style.STROKE);

    evaluator = new FloatEvaluator();

    startAnim();

    }

    //初始化数据点和控制点的位置

    @Override

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {

    super.onSizeChanged(w, h, oldw, oldh);

    centerX = w / 2;

    centerY = h / 2;

    points = new ArrayList<>();

    points.add(new PointF(centerX - 150, centerY));

    points.add(new PointF(centerX - 50, centerY - 300));

    points.add(new PointF(centerX + 50, centerY + 300));

    points.add(new PointF(centerX + 150, centerY));

    colors = new HashMap<>();

    for (int i = 0; i < points.size(); i++) {

    colors.put(i, getRanColor());

    }

    destPoints = new ArrayList<>();

    destPoints.add(points.get(0));

    }

    @Override

    protected void onDraw(Canvas canvas) {

    super.onDraw(canvas);

    //静态的

    drawPoint(canvas, points, Color.BLACK);

    drawLine(canvas, points, Color.GRAY);

    //动态的

    List subData = getSubData(points, fraction);

    drawData(canvas, subData, fraction);

    }

    // 绘制数据点

    private void drawPoint(Canvas canvas, List data, int color) {

    paint.setColor(color);

    paint.setStrokeWidth(20);

    for (int i = 0; i < data.size(); i++) {

    PointF pointF = data.get(i);

    canvas.drawPoint(pointF.x, pointF.y, paint);

    }

    }

    //绘制基准线

    private void drawLine(Canvas canvas, List data, int color) {

    paint.setColor(color);

    paint.setStrokeWidth(4);

    for (int i = 0; i < data.size() - 1; i++) {

    PointF start = data.get(i);

    PointF end = data.get(i + 1);

    canvas.drawLine(start.x, start.y, end.x, end.y, paint);

    }

    }

    //绘制路径

    private void drawPath(Canvas canvas, List data) {

    Path path = new Path();

    PointF start = data.get(0);

    path.moveTo(start.x, start.y);

    for (int i = 1; i < data.size() - 1; i++) {

    PointF point = data.get(i);

    path.lineTo(point.x, point.y);

    }

    paint.setColor(Color.RED);

    paint.setStrokeWidth(4);

    canvas.drawPath(path, paint);

    }

    //迭代绘制集合

    private void drawData(Canvas canvas, List data, float fraction) {

    if (data.size() == 1) {

    drawPoint(canvas, data, Color.BLACK);

    destPoints.add(data.get(0));

    drawPath(canvas, destPoints);

    } else {

    drawLine(canvas, data, colors.get(data.size() - 1));

    //迭代

    List subData = getSubData(data, fraction);

    drawData(canvas, subData, fraction);

    }

    }

    private void startAnim() {

    ValueAnimator animator = ValueAnimator.ofFloat(0, 100);

    animator.setInterpolator(new LinearInterpolator());

    animator.setDuration(5000);

    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

    @Override

    public void onAnimationUpdate(ValueAnimator animation) {

    fraction = animation.getAnimatedFraction();

    invalidate();

    }

    });

    animator.start();

    }

    //生成随机颜色

    private int getRanColor() {

    return 0xff000000 | new Random().nextInt(0x00ffffff);

    }

    //获取子数据源

    private List getSubData(List data, float fraction) {

    List subData = new ArrayList<>();

    for (int i = 0; i < data.size() - 1; i++) {

    PointF start = data.get(i);

    PointF end = data.get(i + 1);

    float x = evaluator.evaluate(fraction, start.x, end.x);

    float y = evaluator.evaluate(fraction, start.y, end.y);

    subData.add(new PointF(x, y));

    }

    return subData;

    }

    }

    1.2.生成贝塞尔曲线-De Casteljau算法

    package com.che.chechengwang.support.view.bezier;

    import android.animation.ValueAnimator;

    import android.content.Context;

    import android.graphics.Canvas;

    import android.graphics.Color;

    import android.graphics.Paint;

    import android.graphics.Path;

    import android.graphics.PointF;

    import android.util.AttributeSet;

    import android.view.View;

    import android.view.animation.LinearInterpolator;

    import java.util.ArrayList;

    import java.util.List;

    /**

    * 生成贝塞尔曲线-De Casteljau算法

    *

    * 作者:余天然 on 16/6/14 下午2:10

    */

    public class BezierGenerater2 extends View {

    private Paint paint;

    private int centerX, centerY;

    private List points;

    private float fraction;

    private List destPoints;

    public BezierGenerater2(Context context, AttributeSet attrs) {

    super(context, attrs);

    init();

    }

    private void init() {

    paint = new Paint();

    paint.setAntiAlias(true);

    paint.setStyle(Paint.Style.STROKE);

    }

    //初始化数据点和控制点的位置

    @Override

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {

    super.onSizeChanged(w, h, oldw, oldh);

    centerX = w / 2;

    centerY = h / 2;

    points = new ArrayList<>();

    points.add(new PointF(centerX - 150, centerY));

    points.add(new PointF(centerX - 50, centerY - 300));

    points.add(new PointF(centerX + 50, centerY + 300));

    points.add(new PointF(centerX + 150, centerY));

    destPoints = new ArrayList<>();

    destPoints.add(points.get(0));

    startAnim();

    }

    @Override

    protected void onDraw(Canvas canvas) {

    super.onDraw(canvas);

    //静态的

    drawPoint(canvas, points, Color.BLACK);

    drawLine(canvas, points, Color.GRAY);

    //动态的

    drawPath(canvas, destPoints);

    }

    // 绘制数据点

    private void drawPoint(Canvas canvas, List data, int color) {

    paint.setColor(color);

    paint.setStrokeWidth(20);

    for (int i = 0; i < data.size(); i++) {

    PointF pointF = data.get(i);

    canvas.drawPoint(pointF.x, pointF.y, paint);

    }

    }

    //绘制基准线

    private void drawLine(Canvas canvas, List data, int color) {

    paint.setColor(color);

    paint.setStrokeWidth(4);

    for (int i = 0; i < data.size() - 1; i++) {

    PointF start = data.get(i);

    PointF end = data.get(i + 1);

    canvas.drawLine(start.x, start.y, end.x, end.y, paint);

    }

    }

    //绘制路径

    private void drawPath(Canvas canvas, List data) {

    Path path = new Path();

    PointF start = data.get(0);

    path.moveTo(start.x, start.y);

    for (int i = 1; i < data.size() - 1; i++) {

    PointF point = data.get(i);

    path.lineTo(point.x, point.y);

    }

    paint.setColor(Color.RED);

    paint.setStrokeWidth(4);

    canvas.drawPath(path, paint);

    }

    private void startAnim() {

    ValueAnimator animator = ValueAnimator.ofFloat(0, 100);

    animator.setInterpolator(new LinearInterpolator());

    animator.setDuration(5000);

    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

    @Override

    public void onAnimationUpdate(ValueAnimator animation) {

    fraction = animation.getAnimatedFraction();

    PointF pointF = deCasteljau(fraction, points);

    destPoints.add(pointF);

    invalidate();

    }

    });

    animator.start();

    }

    //深复制

    private List copyData(List points) {

    List data = new ArrayList<>();

    for (int i = 0; i < points.size(); i++) {

    PointF point = points.get(i);

    data.add(new PointF(point.x, point.y));

    }

    return data;

    }

    //De Casteljau算法

    public PointF deCasteljau(float fraction, List points) {

    List data = copyData(points);

    final int n = data.size();

    for (int i = 1; i <= n; i++) {

    for (int j = 0; j < n - i; j++) {

    data.get(j).x = (1 - fraction) * data.get(j).x + fraction * data.get(j + 1).x;

    data.get(j).y = (1 - fraction) * data.get(j).y + fraction * data.get(j + 1).y;

    }

    }

    return data.get(0);

    }

    }

    1.3.二阶贝塞尔曲线

    package com.che.chechengwang.support.view.bezier;

    import android.content.Context;

    import android.graphics.Canvas;

    import android.graphics.Color;

    import android.graphics.Paint;

    import android.graphics.Path;

    import android.graphics.PointF;

    import android.util.AttributeSet;

    import android.view.MotionEvent;

    import android.view.View;

    /**

    * 二阶贝塞尔曲线

    *

    * 两个数据点和一个控制点

    * 公式:B(t) = (1 - t)^2 * P0 + 2t * (1 - t) * P1 + t^2 * P2, t ∈ [0,1]

    * 作者:余天然 on 16/6/14 上午10:27

    */

    public class Bezier2 extends View {

    private Paint paint;

    private int centerX, centerY;

    private PointF start, end, control;

    public Bezier2(Context context, AttributeSet attrs) {

    super(context, attrs);

    init();

    }

    private void init() {

    paint = new Paint();

    paint.setAntiAlias(true);

    paint.setStyle(Paint.Style.STROKE);

    start = new PointF(0, 0);

    end = new PointF(0, 0);

    control = new PointF(0, 0);

    }

    //初始化数据点和控制点的位置

    @Override

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {

    super.onSizeChanged(w, h, oldw, oldh);

    centerX = w / 2;

    centerY = h / 2;

    start.x = centerX - 200;

    start.y = centerY;

    end.x = centerX + 200;

    end.y = centerY;

    control.x = centerX;

    control.y = centerY - 100;

    }

    //根据触摸位置更新控制点,并提示重绘

    @Override

    public boolean onTouchEvent(MotionEvent event) {

    control.x = event.getX();

    control.y = event.getY();

    invalidate();

    return true;

    }

    @Override

    protected void onDraw(Canvas canvas) {

    super.onDraw(canvas);

    drawPoint(canvas);

    drawGuideLine(canvas);

    drawBezierCurve(canvas);

    }

    // 绘制数据点和控制点

    private void drawPoint(Canvas canvas) {

    paint.setColor(Color.GRAY);

    paint.setStrokeWidth(20);

    canvas.drawPoint(start.x, start.y, paint);

    canvas.drawPoint(end.x, end.y, paint);

    canvas.drawPoint(control.x, control.y, paint);

    }

    //绘制辅助线

    private void drawGuideLine(Canvas canvas) {

    paint.setStrokeWidth(4);

    canvas.drawLine(start.x, start.y, control.x, control.y, paint);

    canvas.drawLine(control.x, control.y, end.x, end.y, paint);

    }

    //绘制贝塞尔曲线

    private void drawBezierCurve(Canvas canvas) {

    paint.setColor(Color.RED);

    paint.setStrokeWidth(4);

    Path path = new Path();

    path.moveTo(start.x, start.y);

    path.quadTo(control.x, control.y, end.x, end.y);

    canvas.drawPath(path, paint);

    }

    }

    1.4.三阶贝塞尔曲线

    package com.che.chechengwang.support.view.bezier;

    import android.content.Context;

    import android.graphics.Canvas;

    import android.graphics.Color;

    import android.graphics.Paint;

    import android.graphics.Path;

    import android.graphics.PointF;

    import android.util.AttributeSet;

    import android.view.MotionEvent;

    import android.view.View;

    import java.util.ArrayList;

    import java.util.List;

    /**

    * 三阶贝塞尔曲线

    *

    * 2个数据点和2个控制点

    * 公式:B(t) = P0 * (1-t)^3 + 3 * P1 * t * (1-t)^2 + 3 * P2 * t^2 * (1-t) + P3 * t^3 代

    * 作者:余天然 on 16/6/14 上午10:27

    */

    public class Bezier3 extends View {

    private Paint paint;

    private int centerX, centerY;

    private List points;

    public Bezier3(Context context, AttributeSet attrs) {

    super(context, attrs);

    init();

    }

    private void init() {

    paint = new Paint();

    paint.setAntiAlias(true);

    paint.setStyle(Paint.Style.STROKE);

    }

    //初始化数据点和控制点的位置

    @Override

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {

    super.onSizeChanged(w, h, oldw, oldh);

    centerX = w / 2;

    centerY = h / 2;

    points = new ArrayList<>();

    points.add(new PointF(centerX - 150, centerY));

    points.add(new PointF(centerX - 50, centerY - 300));

    points.add(new PointF(centerX + 50, centerY + 300));

    points.add(new PointF(centerX + 150, centerY));

    }

    //根据触摸位置更新控制点,并提示重绘

    @Override

    public boolean onTouchEvent(MotionEvent event) {

    PointF control = new PointF(0, 0);

    control.x = event.getX();

    control.y = event.getY();

    double distance1 = getDistance(control, points.get(1));

    double distance2 = getDistance(control, points.get(2));

    if (distance1 < distance2) {

    points.set(1, control);

    } else {

    points.set(2, control);

    }

    invalidate();

    return true;

    }

    @Override

    protected void onDraw(Canvas canvas) {

    super.onDraw(canvas);

    drawPoint(canvas, points, Color.BLACK);

    drawLine(canvas, points, Color.GRAY);

    drawBezierCurve(canvas);

    }

    // 绘制数据点

    private void drawPoint(Canvas canvas, List data, int color) {

    paint.setColor(color);

    paint.setStrokeWidth(20);

    for (int i = 0; i < data.size(); i++) {

    PointF pointF = data.get(i);

    canvas.drawPoint(pointF.x, pointF.y, paint);

    }

    }

    //绘制基准线

    private void drawLine(Canvas canvas, List data, int color) {

    paint.setColor(color);

    paint.setStrokeWidth(4);

    for (int i = 0; i < data.size() - 1; i++) {

    PointF start = data.get(i);

    PointF end = data.get(i + 1);

    canvas.drawLine(start.x, start.y, end.x, end.y, paint);

    }

    }

    //绘制贝塞尔曲线

    private void drawBezierCurve(Canvas canvas) {

    paint.setColor(Color.RED);

    paint.setStrokeWidth(4);

    Path path = new Path();

    path.moveTo(points.get(0).x, points.get(0).y);

    path.cubicTo(points.get(1).x, points.get(1).y, points.get(2).x, points.get(2).y, points.get(3).x, points.get(3).y);

    canvas.drawPath(path, paint);

    }

    //获取两点的距离

    private double getDistance(PointF start, PointF end) {

    return Math.sqrt((end.y - start.y) * (end.y - start.y) + (end.x - start.x) * (end.x - start.x));

    }

    }

    1.5.用贝塞尔曲线拟合圆形

    分成四段3阶贝塞尔曲线

    每一段拟合90度扇形

    5982e2322f3b

    贝塞尔曲线拟合90圆度

    5982e2322f3b

    计算x1的值

    计算过程:

    由公式:B(t) = P0 * (1-t)^3 + 3 * P1 * t * (1-t)^2 + 3 * P2 * t^2 * (1-t) + P3 * t^3

    显然,当t=0.5的时候,应该正好在45度的位置上,

    于是: sin(pi/4) = 0.125(3x1 - 2) + 0.25(3 - 6x1 ) + 0.5(3x1 )

    解出x1=0.55228475

    也就是:

    5982e2322f3b

    根据对称性,可得y1=x1;

    2.自定义视图

    贝塞尔曲线就是PS里面的魔棒工具,UI上的很多曲线,其实都是用贝塞尔曲线画的,既然如此,我们只需要知道UI是怎么画的,让她标注好数据点的位置,那我们就可以原样画出UI效果了。

    贝塞尔曲线的用处,就是动态绘制平滑曲线!并且可以实时控制曲线状态,并可以通过改变控制点的状态实时让曲线进行平滑的状态变化。

    2.1.气泡拖拽效果效果图:

    5982e2322f3b

    这里写图片描述

    5982e2322f3b

    这里写图片描述

    上面的图是盗来的,因为我还不会在手机上录制gif,下面的我的demo的截图:

    5982e2322f3b

    这里写图片描述

    这里:

    p1是初始圆的圆心,p2是拖动圆的圆心

    X是p1p2线段的中点

    AB:与p1p2线段垂直,长度为初始圆的直径

    CD:与p1p2线段垂直,长度为拖动圆的直径

    绘制流程:

    1.绘制p1和p2的圆形

    2.根据A,X,D绘制一条2阶贝塞尔曲线

    3.根据B,X,C绘制另一条2阶贝塞尔曲线

    4.设置path的模式为填充模式

    package com.che.chechengwang.support.view.bezier;

    import android.animation.FloatEvaluator;

    import android.animation.ValueAnimator;

    import android.content.Context;

    import android.graphics.Canvas;

    import android.graphics.Color;

    import android.graphics.Paint;

    import android.graphics.Path;

    import android.graphics.PointF;

    import android.util.AttributeSet;

    import android.view.MotionEvent;

    import android.view.View;

    import android.view.animation.OvershootInterpolator;

    import com.che.chechengwang.support.view.bezier.PointUtil;

    /**

    * 贝塞尔曲线-气泡拖拽

    *

    * 二条2阶贝塞尔曲线

    * 作者:余天然 on 16/6/14 上午10:27

    */

    public class BezierDraggableFlag extends View {

    private Paint paint;

    private int raduis = 40;//气泡的半径

    private double distance;//记录拉动的距离

    private double raduisTmp;//临时的半径

    private int maxDistance = 800;//拉断的距离

    private PointF p1, p2;//圆心

    private PointF pA, pB, pC, pD, pX;//控制点

    private double distanceBackup;

    private PointF p2Backup;

    public BezierDraggableFlag(Context context, AttributeSet attrs) {

    super(context, attrs);

    init();

    }

    //初始化圆心的位置

    private void init() {

    paint = new Paint();

    paint.setAntiAlias(true);

    p1 = new PointF(600, 400);

    p2 = new PointF(600, 400);

    }

    @Override

    public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction()) {

    case MotionEvent.ACTION_DOWN:

    break;

    case MotionEvent.ACTION_MOVE:

    p2.x = event.getX();

    p2.y = event.getY();

    distance = PointUtil.getDistance(p1, p2);

    invalidate();

    break;

    case MotionEvent.ACTION_UP:

    if (distance < maxDistance) {

    p2Backup = new PointF(p2.x, p2.y);

    distanceBackup = distance;

    startAnim();

    }

    break;

    }

    return true;

    }

    @Override

    protected void onDraw(Canvas canvas) {

    super.onDraw(canvas);

    if (distance < maxDistance) {

    calculatePoint();

    drawBefore(canvas);

    } else {

    drawAfter(canvas);

    }

    }

    //计算控制点的位置

    private void calculatePoint() {

    double raduisScale = 1 - distance / maxDistance;

    raduisTmp = raduis * raduisScale;

    pA = PointUtil.getRotatePoint(p1, p2, raduisTmp, Math.PI / 2);

    pB = PointUtil.getRotatePoint(p1, p2, raduisTmp, -Math.PI / 2);

    pC = PointUtil.getRotatePoint(p2, p1, raduis, -Math.PI / 2);

    pD = PointUtil.getRotatePoint(p2, p1, raduis, Math.PI / 2);

    pX = PointUtil.getCenterPoint(p1, p2);

    }

    //拉断之后的绘制

    private void drawAfter(Canvas canvas) {

    paint.setColor(Color.RED);

    paint.setStyle(Paint.Style.FILL);

    paint.setStrokeWidth(4);

    canvas.drawCircle(p2.x, p2.y, raduis, paint);

    }

    //拉断之前的绘制

    private void drawBefore(Canvas canvas) {

    //端点

    // paint.setColor(Color.GRAY);

    // paint.setStyle(Paint.Style.STROKE);

    // paint.setStrokeWidth(20);

    // canvas.drawPoint(p1.x, p1.y, paint);

    // canvas.drawPoint(p2.x, p2.y, paint);

    // canvas.drawPoint(pX.x, pX.y, paint);

    //辅助线

    paint.setColor(Color.GRAY);

    paint.setStyle(Paint.Style.STROKE);

    paint.setStrokeWidth(4);

    canvas.drawLine(p1.x, p1.y, p2.x, p2.y, paint);

    //文字

    // paint.setColor(Color.BLACK);

    // paint.setStyle(Paint.Style.FILL);

    // paint.setStrokeWidth(2);

    // paint.setTextSize(30);

    // canvas.drawText("A", pA.x, pA.y, paint);

    // canvas.drawText("B", pB.x, pB.y, paint);

    // canvas.drawText("C", pC.x, pC.y, paint);

    // canvas.drawText("D", pD.x, pD.y, paint);

    // canvas.drawText("X", pX.x, pX.y, paint);

    // canvas.drawText("p1", p1.x, p1.y, paint);

    // canvas.drawText("p2", p2.x, p2.y, paint);

    //圆形

    paint.setColor(Color.RED);

    paint.setStyle(Paint.Style.FILL);

    paint.setStrokeWidth(4);

    canvas.drawCircle(p1.x, p1.y, (float) raduisTmp, paint);

    canvas.drawCircle(p2.x, p2.y, raduis, paint);

    //贝塞尔曲线

    paint.setColor(Color.RED);

    paint.setStyle(Paint.Style.FILL);

    paint.setStrokeWidth(4);

    Path path = new Path();

    path.moveTo(pA.x, pA.y);

    path.quadTo(pX.x, pX.y, pD.x, pD.y);

    path.lineTo(pC.x, pC.y);

    path.quadTo(pX.x, pX.y, pB.x, pB.y);

    path.lineTo(pA.x, pA.y);

    canvas.drawPath(path, paint);

    }

    //放开之后,如果没有拉断,就恢复初始状态

    private void startAnim() {

    final FloatEvaluator evaluator = new FloatEvaluator();

    ValueAnimator animator = ValueAnimator.ofFloat(0, 100);

    animator.setInterpolator(new OvershootInterpolator());

    animator.setDuration(100);

    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

    @Override

    public void onAnimationUpdate(ValueAnimator animation) {

    float fraction = animation.getAnimatedFraction();

    p2.x = evaluator.evaluate(fraction, p2Backup.x, p1.x);

    p2.y = evaluator.evaluate(fraction, p2Backup.y, p1.y);

    distance = evaluator.evaluate(fraction, distance, 0);

    invalidate();

    }

    });

    animator.start();

    }

    }

    这里用到了一个工具类:

    package com.che.chechengwang.support.view.bezier;

    import android.graphics.PointF;

    /**

    * 点计算工具类

    *

    * 作者:余天然 on 16/6/15 下午2:33

    */

    public class PointUtil {

    //获取旋转后的点

    public static PointF getRotatePoint(PointF p1, PointF p2, double raduis, double radians) {

    double oldRadians = getPointDegree(p1, p2);

    double newRadians = oldRadians + radians;

    float x = (float) (raduis * Math.cos(newRadians));

    float y = (float) (raduis * Math.sin(newRadians));

    return new PointF(p1.x + x, p1.y + y);

    }

    //获取中间的点

    public static PointF getCenterPoint(PointF p1, PointF p2) {

    float x = (p1.x + p2.x) / 2;

    float y = (p1.y + p2.y) / 2;

    return new PointF(x, y);

    }

    //获取两点的角度-返回的是弧度制

    public static double getPointDegree(PointF p1, PointF p2) {

    double scale = (p2.y - p1.y) / (p2.x - p1.x);

    return Math.atan(scale);

    }

    //获取两点的距离

    public static double getDistance(PointF start, PointF end) {

    return Math.sqrt((end.y - start.y) * (end.y - start.y) + (end.x - start.x) * (end.x - start.x));

    }

    }

    2.2.指示器效果目标效果:

    5982e2322f3b

    这里写图片描述

    这个以后再来玩,其实有了上面的气泡拖拽效果,实现这个效果很简单的,有兴趣的朋友完全可以根据我上面的效果来实现它。

    随便再给大家分享一个学习android自定义View相关知识的好网站:有心课堂-三杆火枪干掉自定义View,传递给你的不仅仅是技术!

    菜鸟一枚,水平有限,欢迎大家指出博文中的不足之处,小鱼将不胜感激!@qq:630709658

    参考目录:

    展开全文
  • 下面以二阶贝塞尔曲线说明: 步骤一:在平面内选3个不同线的点并且依次用线段连接。 步骤二:在AB和BC线段上找出点D和点E,使得 AD/AB = BE/BC 步骤三:连接DE,在DE上寻找点F,F点需要满足:DF/DE = AD/AB = BE/BC...
  • 二阶贝塞尔曲线为例 如图,在p0,p1之间移动着一个点,我们先称之为a0,同样在p1,p2之间移动着一个点,我们称之为a1。他们需要满足的条件是这样的,在移动中,保证线段p0a0:p0p1=p1a1:p1p2=X ,这个比值X是从0...
  • 贝塞尔曲线实现原理

    2021-03-12 20:07:48
    如图,一阶(两点)贝塞尔、二阶(三点)贝塞尔、三阶(四点)贝塞尔、四阶(五点)贝塞尔 Bezier原理其实不复杂~ 一阶贝塞尔(直线) 一阶贝塞尔由两个点确定:P0P0P0...二阶贝塞尔曲线二阶贝塞尔由3个点确定:P.
  • 贝塞尔曲线的数学原理 我相信所有射鸡师们都知道贝塞尔曲线是什么,习惯用PS的会用钢笔...在数学中,贝塞尔又分为很多种,一阶贝塞尔曲线、二阶贝塞尔曲线、三阶贝塞尔曲线····等等等等,除了一阶贝塞尔是直线外...
  • Android 绘图贝塞尔曲线简单使用 ...二阶贝塞尔曲线:二阶贝塞尔曲线原理图是这样的:(图片取自网络)由上图看,P0是起点,P2是终点。P1是控制点,t是一个系数,表示从0-1的变化过程,红色的线就是最终画出的
  • 贝塞尔曲线

    2021-03-07 14:05:49
    二阶贝塞尔曲线(抛物线): 原理:由 P0 至 P1 的连续点 Q0,描述一条线段。 由 P1 至 P2 的连续点 Q1,描述一条线段。 由 Q0 至 Q1 的连续点 B(t),描述一条二次贝塞尔曲线。 经验:P1-P0为曲线在P0处的...
  • n阶贝塞尔曲线

    2018-08-18 21:49:00
    贝塞尔曲线(Bézier curve)是由法国数学家Pierre Bézier所提出,类似于Photoshop软件中的钢笔工具,不过钢笔工具仅仅只是用了二阶贝塞尔曲线. 原理 在我们写代码之前还是了解一下原理为好,所以贝塞尔曲线的原理就是...
  • 贝塞尔曲线公式

    2016-01-25 16:13:00
    二阶贝塞尔曲线原理:由 P0 至 P1 的连续点 P3,描述一条线段。 由 P1 至 P2 的连续点 P4,描述一条线段。 由 P3 至 P4 的连续点 P5,描述一条二次贝塞尔曲线。 公式推导: 求P5,P5 根据一阶贝塞尔...
  • 一、序言 本篇只讲述贝塞尔曲线数学公式的...二、贝塞尔曲线原理 原文链接:https://www.jianshu.com/p/6075f9782743 A. 二阶贝塞尔曲线 要素:1 个起点,1 个终点,1 个控制点 知识点 三阶的话就是 2 个控制...
  • 使用贝塞尔曲线实现的水波浪效果,在很多杀毒软件的进度条显示中都有应用: 这个效果呢以前在有一个项目中需要实现过,当时是...贝塞尔曲线原理(实现图真漂亮) 我们常用的是二阶贝塞尔曲线,其推导公式为: ...
  • 二阶贝塞尔曲线公式 B(t)=(1 – t)²Po + 2t(1 – t)P1 + t²P2,t∈[0,1] 可转换为 B(t)= (1-t)[(1-t)Po + tP1] + t[(1-t)P1 + tP2] 二阶贝塞尔曲线示例图 气泡实现解析 实现过程 先通过上面的...
  • 贝塞尔曲线入门-笔记

    2018-05-25 17:24:12
    代码 Q:什么是贝塞尔曲线? A:贝塞尔曲线奠定了计算机绘图,简单说他可以将任何复杂的图像用精确的数学语言进行描述 ...贝塞尔曲线在Path中方法 ... 二阶贝塞尔 ...贝塞尔曲线原理 贝塞尔曲线是...
  • 三阶贝塞尔曲线

    千次阅读 2019-09-12 18:11:16
    P3(x,y),其中p1和p2是两个控制点,相比二阶贝塞尔曲线多了一个控制点, 示例 /** * 三阶贝塞尔曲线 * * 需要两个控制点 * */ public class BSE3View extends View { /*起点*/ int st...
  • 贝塞尔曲线画画

    2020-04-27 14:44:31
    例如PS中的钢笔工具,它的原理就是二阶贝塞尔曲线。 一阶贝塞尔曲线 一阶贝塞尔曲线描述的是从p0到p1的连续点,是一条直线。公式如下: B(t)=(1−t)p0+tp1,tϵ(0,1)B(t)=(1-t)p_{0}+tp_{1},t\epsilon (0,1)B(t)=(1...
  • 贝塞尔曲线_简单理解入门_lemonen

    千次阅读 2017-07-05 15:18:37
    昨天刚刚研究了一下贝塞尔曲线的原理,把二阶贝塞尔曲线的公式推导出来 贝赛尔曲线(Bézier曲线)是电脑图形学中相当重要的参数曲线。更高维度的广泛化贝塞尔曲线就称作贝塞尔曲面,其中贝塞尔三角是一种特殊的...
  • 以一个简单的贝塞尔曲线为例,二阶曲线原理 贝塞尔曲线很多功能都会用到,比如小火箭发射,再比如淘宝的购物车功能 所幸的是Android有封装好的贝塞尔曲线,我们直接拿过来用就可以了: //二阶贝赛尔 public void ...
  • 自定义视图-贝塞尔曲线

    千次阅读 2016-06-15 16:26:18
    APK下载地址1....意义:由 P0 至 P1 的连续点, 描述的一条线段二阶贝塞尔曲线(抛物线):原理:由 P0 至 P1 的连续点 Q0,描述一条线段。 由 P1 至 P2 的连续点 Q1,描述一条线段。 由 Q0 至 Q1
  • 二阶曲线: ①在AB上任选一个点 D。计算该点到线段起点的距离 AD,与该线段总长 AB 的比例t。 ②从BC上找出对应的点 E,使得 AD:AB=BE:BC=t。 下面进行公式推导: P‘0 对应D点坐标,P‘1对应E点坐标。 ...
  • 二阶贝塞尔曲线(抛物线) 二次方贝兹曲线的路径由给定点P0、P1、P2的函数B(t) 原理:由 P0 至 P1 的连续点 Q0 描述一条线段;  由P1 至 P2 的连续点 Q1 描述一条线段。  由Q0 至 Q1 的连续点 B(t) 描述...
  • 贝塞尔曲线能干什么 贝塞尔曲线作用十分广泛,简单举几个的栗子: QQ小红点拖拽效果 一些炫酷的下拉刷新控件 阅读软件的翻书效果 一些平滑的折线图的制作 很多炫酷的动画效果 ...二阶曲线原理: 二...
  • 原理图: 看了半天网上的讲解,我也不是很懂,上面的公式 ,大概让我知道了些,原来这平滑的...1.二阶贝塞尔曲线绘制 谷歌封装了一个方法quadTo,给出起点,控制点以及终点,就可以直接绘制package com.wx.bezierma
  • 前言 很久之前就看到过实现原理了,就是没有动手去实现一下。最近又看到了贝塞尔曲线相关...二阶贝塞尔曲线公式 B(t)=(1 - t)²Po + 2t(1 - t)P1 + t²P2,t∈[0,1] 可转换为 B(t)= (1-t)[(1-t)Po + t...

空空如也

空空如也

1 2 3
收藏数 49
精华内容 19
关键字:

二阶贝塞尔曲线原理