What is a Bezier curve

Simple bezier curve consists of a line segment and node, the node can be dragged to stand, and line segment as a scalable elastic, visual impact, we can use it to draw all kinds of unexpected curve, there would not be in list of Bessel curve definition and derivation, interested friends can baidu itself. Bessel curves can be divided into first-order Bessel curves, second-order Bessel curves, third-order Bessel curves and even multi-order Bessel curves. Very friendly to Android development and has packaged a simple API for us to use.

AndroidApi

Second-order Bessel rendering API:

Formula:

B (t) is the current motion coordinate P0 represents the starting fixed point, P1 represents the bezier curve control point, and P2 represents the end fixed point.

In simple terms, we determine the fixed point (startX,startY), and the terminal fixed point (endX,endY). It is the control point (controllX,controllY) that determines the curve change. We change the shape of bezier curve by changing the control point.

  mBezierPath.moveTo(startX,startY);
    mBezierPath.quadTo(controllX,controllY,endX,endY);
    canvas.drawPath(mBezierPath, mCustonPaint);
Copy the code

Third-order Bezier drawing API:

Formula:

B (t) is the current motion coordinate P0 represents the starting fixed point, P1 represents the left control point of Bessel curve, P2 represents the right control point of Bessel curve, and P3 represents the end fixed point.

In simple terms, we determine the fixed point (startX, startY), the termination fixed point (endX,endY)), and determine the curve change is the control point (left control point (eventLeftX,eventLeftY), Right control point) (eventRightX,eventRightY), we change the shape of the Bezier curve by changing the control point.

 path.moveTo(startX, startY);
    path.cubicTo(eventLeftX, eventLeftY, eventRightX, eventRightY, endX, endY);
    canvas.drawPath(path, mCustonPaint);
Copy the code

Bezier curve principle

First order Bezier curve

Schematic diagram:

Principle: T in a linear Bezier curve function passes through the curve described by B(t) from P0 to P1. For example, when t=0.25, B(t) is one-fourth of a path from point P0 to P1. Just like a continuous t from 0 to 1, B of T describes a line from P0 to P1.

Implementation: The first order Bezier curve is actually a straight line. The implementation is quite simple and will not be demonstrated here.

Second order Bezier curve

Schematic diagram:

Principle:

To construct a quadratic Bezier curve, a linear Bezier curve can be described by using the intermediate points Q0 and Q1 as t from 0 to 1 and the continuous point Q0 from P0 to P1. The continuous point Q1 from P1 to P2 describes a linear Bezier curve. Describe a quadratic Bessel curve from the continuous point B(t) Q0 to Q1.

Implementation:

Let’s draw the Bezier curve using the Android APIThe renderings are as follows:

Code: Very simple to implement, here is the core code

@Override protected void onDraw(Canvas canvas) { Path path = new Path(); path.reset(); path.moveTo(startX, startY); path.quadTo(eventX, eventY, endX, endY); canvas.drawPath(path, mCustonPaint); canvas.drawCircle(startX, startY, 25, mCustomCirlePaint); DrawCircle (endX, endY, 25, mCustomCirlePaint); DrawCircle (eventX, eventY, 25, mCustomCirlePaint); DrawLine (startX, startY, eventX, eventY, mCustomLinePaint); drawLine(startX, startY, eventX, eventY, mCustomLinePaint); DrawLine (eventX, eventY, endX, endY, mCustomLinePaint); } @override public Boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: eventX = (int) event.getX(); eventY = (int) event.getY(); postInvalidate(); break; } return true; }Copy the code

Third order Bezier curve

Schematic diagram:

Principle:

A Bessel curve of order two is essentially adding a side line to the second order.

Implementation: We use the Android API to draw the Bezier curve

The renderings are as follows:

Core code implementation:

@Override protected void onDraw(Canvas canvas) { Path path = new Path(); path.moveTo(startX, startY); path.cubicTo(eventLeftX, eventLeftY, eventRightX, eventRightY, endX, endY); canvas.drawPath(path, mCustonPaint); canvas.drawCircle(startX, startY, 25, mCustomCirlePaint); DrawCircle (endX, endY, 25, mCustomCirlePaint); DrawCircle (eventLeftX, eventLeftY, 25, mCustomCirlePaint); DrawCircle (eventRightX, eventRightY, 25, mCustomCirlePaint); DrawLine (startX, startY, eventLeftX, eventLeftY, mCustomLinePaint); drawLine(startX, startY, eventLeftX, eventLeftY, mCustomLinePaint); DrawLine (eventRightX, eventRightY, endX, endY, mCustomLinePaint); DrawLine (eventLeftX, eventLeftY, eventRightX, eventRightY, mCustomLinePaint); // Path.reset (); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: if (isMoveLeft) { eventLeftX = (int) event.getX(); eventLeftY = (int) event.getY(); } else { eventRightX = (int) event.getX(); eventRightY = (int) event.getY(); } postInvalidate(); break; } return true; }Copy the code

So here we have a simple Bezier curve.

Detailed code

Second order Bezier curve

/ * * * @ the description: * @author MRyan * @date 2020/4/10:56 * @version 1.0 */ Public Class BaseBezier2 extends View {private int mCustomSize; private int mCustomColor; private Paint mCustonPaint; private Paint mCustomCirlePaint; private int mSize; private int weight; private int height; private int startX; private int startY; private int endX; private int endY; private int eventX; private int eventY; private Paint mCustomLinePaint; private Boolean isClean = false; public BaseBezier2(Context context) { super(context); } public BaseBezier2(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initAttr(context, attrs); initPaint(); } public BaseBezier2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, 0); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); weight = MeasureSpec.getSize(widthMeasureSpec); height = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(weight, height); startX = weight / 2 - 500; startY = height / 2; endX = weight / 2 + 500; endY = height / 2; eventX = weight / 2; eventY = height / 2 - 500; } @Override protected void onDraw(Canvas canvas) { Path path = new Path(); path.reset(); path.moveTo(startX, startY); path.quadTo(eventX, eventY, endX, endY); canvas.drawPath(path, mCustonPaint); canvas.drawCircle(startX, startY, 25, mCustomCirlePaint); DrawCircle (endX, endY, 25, mCustomCirlePaint); DrawCircle (eventX, eventY, 25, mCustomCirlePaint); DrawLine (startX, startY, eventX, eventY, mCustomLinePaint); drawLine(startX, startY, eventX, eventY, mCustomLinePaint); DrawLine (eventX, eventY, endX, endY, mCustomLinePaint); } @override public Boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: eventX = (int) event.getX(); eventY = (int) event.getY(); postInvalidate(); break; } return true; } private void initPaint() { mCustonPaint = new Paint(); mCustonPaint.setColor(mCustomColor); mCustonPaint.setAntiAlias(true); mCustonPaint.setStrokeWidth(20); mCustonPaint.setStyle(Paint.Style.STROKE); mCustomCirlePaint = new Paint(); mCustomCirlePaint.setColor(Color.parseColor("#ffffff")); mCustomCirlePaint.setAntiAlias(true); mCustomCirlePaint.setStrokeWidth(17); mCustomCirlePaint.setStyle(Paint.Style.STROKE); mCustomLinePaint = new Paint(); mCustomLinePaint.setColor(Color.parseColor("#ffffff")); mCustomLinePaint.setAntiAlias(true); mCustomLinePaint.setStrokeWidth(13); } private void initAttr(Context context, AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BaseBezier2); mCustomColor = typedArray.getColor(R.styleable.BaseBezier2_custom_color2, mCustomColor); mCustomSize = (int) typedArray.getDimension(R.styleable.BaseBezier2_custom_size2, mCustomSize); typedArray.recycle(); } public void cleanSub() { if (onIsCleanSubListener ! = null) { onIsCleanSubListener.onCleanSub(isClean); } isClean = false; mCustomLinePaint.setAlpha(255); postInvalidate(); } public void Sub() { if (onIsCleanSubListener ! = null) { onIsCleanSubListener.onCleanSub(isClean); } isClean = true; mCustomLinePaint.setAlpha(0); postInvalidate(); } public void iscleanSub() {if (isClean) {cleanSub(); } else { Sub(); } /** * Public onIsCleanSubListener2 onIsCleanSubListener; public interface onIsCleanSubListener2 { void onCleanSub(Boolean isclean); } public void setOnIsCleanSubListener(onIsCleanSubListener2 onIsCleanSubListener) { this.onIsCleanSubListener = onIsCleanSubListener; }}Copy the code

Third order Bezier curve

/ * * * @ the description: * @author MRyan * @date 2020/4/10:56 * @version 1.0 */ Public Class BaseBezier3 extends View {private int mCustomSize; private int mCustomColor; private Paint mCustonPaint; private Paint mCustomCirlePaint; private int mSize; private int weight; private int height; private int startX; private int startY; private int endX; private int endY; private int eventLeftX; private int eventLeftY; private int eventRightX; private int eventRightY; private Paint mCustomLinePaint; private boolean isMoveLeft = true; private boolean isClean = false; public BaseBezier3(Context context) { super(context); } public BaseBezier3(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initAttr(context, attrs); initPaint(); } public BaseBezier3(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, 0); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); weight = MeasureSpec.getSize(widthMeasureSpec); height = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(weight, height); startX = weight / 2 - 500; startY = height / 2; endX = weight / 2 + 500; endY = height / 2; eventLeftX = weight / 2 / 2; eventLeftY = height / 2 - 500; eventRightX = weight / 4 * 3; eventRightY = height / 2 - 500; } @Override protected void onDraw(Canvas canvas) { Path path = new Path(); path.moveTo(startX, startY); path.cubicTo(eventLeftX, eventLeftY, eventRightX, eventRightY, endX, endY); canvas.drawPath(path, mCustonPaint); canvas.drawCircle(startX, startY, 25, mCustomCirlePaint); DrawCircle (endX, endY, 25, mCustomCirlePaint); DrawCircle (eventLeftX, eventLeftY, 25, mCustomCirlePaint); DrawCircle (eventRightX, eventRightY, 25, mCustomCirlePaint); DrawLine (startX, startY, eventLeftX, eventLeftY, mCustomLinePaint); drawLine(startX, startY, eventLeftX, eventLeftY, mCustomLinePaint); DrawLine (eventRightX, eventRightY, endX, endY, mCustomLinePaint); DrawLine (eventLeftX, eventLeftY, eventRightX, eventRightY, mCustomLinePaint); // Path.reset (); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: if (isMoveLeft) { eventLeftX = (int) event.getX(); eventLeftY = (int) event.getY(); } else { eventRightX = (int) event.getX(); eventRightY = (int) event.getY(); } postInvalidate(); break; } return true; } public void moveLeft() {isMoveLeft = true; } public void moveRight() {isMoveLeft = false; } private void initPaint() { mCustonPaint = new Paint(); mCustonPaint.setColor(mCustomColor); mCustonPaint.setAntiAlias(true); mCustonPaint.setStrokeWidth(20); mCustonPaint.setStyle(Paint.Style.STROKE); mCustomCirlePaint = new Paint(); mCustomCirlePaint.setColor(Color.parseColor("#ffffff")); mCustomCirlePaint.setAntiAlias(true); mCustomCirlePaint.setStrokeWidth(17); mCustomCirlePaint.setStyle(Paint.Style.STROKE); mCustomLinePaint = new Paint(); mCustomLinePaint.setColor(Color.parseColor("#ffffff")); mCustomLinePaint.setAntiAlias(true); mCustomLinePaint.setStrokeWidth(13); } private void initAttr(Context context, AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BaseBezier3); mCustomColor = typedArray.getColor(R.styleable.BaseBezier3_custom_color3, mCustomColor); mCustomSize = (int) typedArray.getDimension(R.styleable.BaseBezier3_custom_size3, mCustomSize); typedArray.recycle(); } public void cleanSub() { if (onIsCleanSubListener ! = null) { onIsCleanSubListener.onCleanSub(isClean); } isClean = false; mCustomLinePaint.setAlpha(255); postInvalidate(); } public void Sub() { if (onIsCleanSubListener ! = null) { onIsCleanSubListener.onCleanSub(isClean); } isClean = true; mCustomLinePaint.setAlpha(0); postInvalidate(); } public void iscleanSub() {if (isClean) {cleanSub(); } else { Sub(); } /** * public onIsCleanSubListener; public interface onIsCleanSubListener { void onCleanSub(Boolean isclean); } public void setOnIsCleanSubListener(BaseBezier3.onIsCleanSubListener onIsCleanSubListener) { this.onIsCleanSubListener  = onIsCleanSubListener; }}Copy the code

You can do a lot of nice things with bezier curves, for example

In the next video, we’ll implement these two animations together, and I’ll see you in the next video.

Attach the project source code

Program source code