Zero, preface,

1. The Bezier curve is a “sword in the stone”, so to pull it out will make your drawing more powerful.

2. I’m going to fight Bezier curve for 300 rounds today, and add it to my drawing army. 3. From now on, Android’s five main drawing skills :Canvas, Path, Paint, Color, and Bezier are assembled. 4. The source code of this project is shown in article 1, the view source code is in the VIEW package, and the analysis tool is in the Analyze package


First, the first experience of besser’s three curves

1.No grid, no curveWithout further ado, let’s go to the grid plus coordinates
/** * Author: Zhang Feng Jiete Lie <br/> * Time: 2018/11/160016:9:04 <br/> * Email: [email protected]<br/> * Description: Public class SimpleCubicView extends View {private Point mCoo = new Point(500, 500); // Private Picture mCooPicture; // Canvas element private grid Picture; // Canvas element private Paint mHelpPint; // Private Paint mPaint; // Private Path mPath; Public SimpleCubicView(Context Context) {this(Context, null); } public SimpleCubicView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); Private void init() {// initialize the main paintbrush mPaint = new Paint(paint.anti_alias_flag); mPaint.setColor(Color.BLUE); mPaint.setStrokeWidth(5); // Initialize the main Path mPath = new Path(); // Initialize helper mHelpPint = helpdraw.gethelppint (color.red); mCooPicture = HelpDraw.getCoo(getContext(), mCoo); mGridPicture = HelpDraw.getGrid(getContext()); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); canvas.translate(mCoo.x, mCoo.y); //TODO ----drawSomething canvas.restore(); HelpDraw.draw(canvas, mGridPicture, mCooPicture); }}Copy the code
2. Analyze a passage of three bessers

A cubic Bezier curve is controlled by four points. What do the four points do?

Point p0 = new Point(0, 0); Point p1 = new Point(200, 200); Point p2 = new Point(300, -100); Point p3 = new Point(500, 300); //onDraw: mpath.moveto (p0.x, p0.y); mPath.cubicTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); canvas.drawPath(mPath, mPaint);Copy the code

In case it doesn’t make any sense: Now draw the four control points (red) :

mHelpPint.setStrokeWidth(10);
HelpDraw.drawPos(canvas, mHelpPint, p0, p1, p2, p3);
Copy the code

Isn’t that interesting — add two lines:

mHelpPint.setStrokeWidth(2);
HelpDraw.drawLines(canvas, mHelpPint, p0, p1, p2, p3);
Copy the code

Summary: P0: first point, P3: final point, P1: control point 1, P2: control point 2


2. Dynamic effect: the most elegant realization of any cubic Bezier curve

I’ve seen any piece of someone’s Bezier curve three times before, and I’ve had to hit a button to switch between dots,

Now, I’m going to do a three times bezier curve with four points, which is very elegant, so you can understand the judgment of the point domain

1. Determine whether a point is in a circle
/ * * * determine whether a radius of r round at some Point within the scope of * * * @ @ param SRC target param DST active Point * * @ param r radius/public static Boolean judgeCircleArea (Point  src, Point dst, float r) { return disPos2d(src.x, src.y, dst.x, dst.y) <= r; } distance function between two points / * * * * / public static float disPos2d (float float x1, y1, float x2, float y2) { return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); }Copy the code
2. Touch events dynamically change the point position:
SRC = new Point(0, 0); // Add member variable Point SRC = new Point(0, 0); @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: src.x = (int) event.getX() - mCoo.x; src.y = (int) event.getY() - mCoo.y; break; case MotionEvent.ACTION_MOVE: if (judgeCircleArea(src, p0, 30)) { setPos(event, p0); } if (judgeCircleArea(src, p1, 30)) { setPos(event, p1); } if (judgeCircleArea(src, p2, 30)) { setPos(event, p2); } if (judgeCircleArea(src, p3, 30)) { setPos(event, p3); } mPath.reset(); src.x = (int) event.getX() - mCoo.x; src.y = (int) event.getY() - mCoo.y; invalidate(); break; } return true; } /** * set @param event * @param p */ private void setPos(MotionEvent event, Point p) { p.x = (int) event.getX() - mCoo.x; p.y = (int) event.getY() - mCoo.y; }Copy the code

Okay, that’s it, isn’t it? It’s over before it starts.


Three, Bezier curve actual combat 1: (primary: sports)

1. The image:

First select the satisfied half and record four points:

Point c1p0 = new Point(0, 0);
Point c1p1 = new Point(300, 0);
Point c1p2 = new Point(150, -200);
Point c1p3 = new Point(300, -200);
Copy the code
2. How to achieve the following effect?

Draw a bezier curve on the basis of the original, requiring that the new control point 1(denoting: C2P1) and C1p2 are symmetric about C1p3. x

X +c1p2.x)/2 =c1p3.x c2p2.y = c1p2.y =c1p3.x*2-c1p2.x C2p2) and c1p1 are symmetric about c1p3.x and the new ending point (denoted as: c2p3) and c1p0 are symmetric about c1p3.x

private void reflectY( Point p0, Point p1, Point p2, Point p3, Path path) {
    path.cubicTo(p3.x * 2 - p2.x, p2.y, p3.x * 2 - p1.x, p1.y, p3.x * 2 - p0.x, p0.y);
}
Copy the code
3. A protruding piece of animation that slowly flattens out

Imagine that all you need to do is move c1P2 and C1P3 down together. To move, without a second thought, the ValueAnimator goes

Well, it’s kind of like doing push-ups, and it’s pretty easy to do:

MAnimator = valueAnimator.offloat (1, 0); mAnimator.setDuration(2000); mAnimator.setRepeatMode(ValueAnimator.REVERSE); mAnimator.setRepeatCount(-1); mAnimator.addUpdateListener(a -> { float rate = (float) a.getAnimatedValue(); c1p2.y = -(int) (rate * 200); c1p3.y = -(int) (rate * 200); mPath.reset(); invalidate(); });Copy the code

4. Play around

The source code is at the end of the text, the file is Lever1Cubicview.java, you can download, run their own play, to enhance the sense of the Bezier cubic curve

All right, the appetizers are over, now it’s time for the dinner, which, you read it right, has just begun.


4. Advanced: Elegant use of the third-order Bezier:

Attention: high energy ahead, non-combatants please prepare melon seeds, drinks, peanuts…

1. Third-order Bezier drawing circles:

Look at the picture below, and you might say, “Gee, I use canvas to paint minutes and seconds, can you believe it?”

Boss, I believe… And looked down

2. How to draw multiple Bezier curves gracefully

Here are four bezier curves of the circle, and you can see that the advantage is to change the shape at will

However, if you put all the points in mpath.cubicto (), more lines can cause chaos. It is better to manage them in a unified way. The first thing that comes to mind is that the three points of each line are divided into three member variables, but it is still difficult to maintain. Two dimensions, two points in each of them.

Private static float rate = 0.551915024494f; private static float rate = 0.551915024494f; /** * private static final float[][] CIRCLE_ARRAY = {// 1, rate},// control point 1 {1 - rate, rate}, {1}, / / control points 2 1, 1}, / / the finish line / / 1 - paragraph 2 {1 + rate, 1}, {2, rate} / / control points 1, 2 {2, 0} / / control points, / / / / end line {2, 2 - the second paragraph {to}, / / a control point 1 1 + rate, 1}, / / a control point 2 {1, 1}, / / / / 3 - the fourth section of the line end {1 - rate, 1}, / / control points 1 {0, to}, / / a control point 2 {0, 0} / / finish};Copy the code
2. Just draw a loop

See some drawing method on the net, the point is very messy, look at laborious also obscure.

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.save();
    canvas.translate(mCoo.x, mCoo.y);

    mPaint.setStyle(Paint.Style.STROKE);
    mPath.lineTo(0, 0);
    for (int i = 0; i < CIRCLE_ARRAY.length / 3; i++) {
        mPath.cubicTo(
                r * CIRCLE_ARRAY[3*i][0], r * CIRCLE_ARRAY[3*i][1],
                r * CIRCLE_ARRAY[3*i + 1][0], r * CIRCLE_ARRAY[3*i + 1][1],
                r * CIRCLE_ARRAY[3*i + 2][0], r * CIRCLE_ARRAY[3*i + 2][1]);
    }
    canvas.drawPath(mPath, mPaint);
    canvas.restore();
}
Copy the code
3. If you can control it, play with it

It’s not that hard to transform it, the key is to make it more obvious by adding auxiliary dots and lines. It’s a hell of a way to show it to everyone, right

MAnimator = valueAnimator.offloat (1, 0); mAnimator.setDuration(2000); mAnimator.setRepeatMode(ValueAnimator.REVERSE); mAnimator.setRepeatCount(-1); mAnimator.addUpdateListener(a -> { runNum = (float) a.getAnimatedValue(); mPath.reset(); invalidate(); }); For (int I = 0; i < CIRCLE_ARRAY.length / 3; i++) { mPath.cubicTo( r * runNum * CIRCLE_ARRAY[3 * i][0], r * runNum * CIRCLE_ARRAY[3 * i][1], r * runNum * CIRCLE_ARRAY[3 * i + 1][0], r * runNum * CIRCLE_ARRAY[3 * i + 1][1], r * CIRCLE_ARRAY[3 * i + 2][0], r * CIRCLE_ARRAY[3 * i + 2][1]); }Copy the code
4. Love — I was just fooling around, now I have to be serious:

If you just take the end of the third line and move it down, you can think of something, right

MPath. CubicTo (// cubicTo # r * CIRCLE_ARRAY[0][0], r * CIRCLE_ARRAY[0][1], r * CIRCLE_ARRAY[1][1], r * CIRCLE_ARRAY[1][1], r * CIRCLE_ARRAY[2][0], r * CIRCLE_ARRAY[2][1]); MPath. CubicTo (// cubicTo ii r * CIRCLE_ARRAY[3][0], r * CIRCLE_ARRAY[3][1], r * CIRCLE_ARRAY[4][0], r * CIRCLE_ARRAY[4][1] r * CIRCLE_ARRAY[5][0], r * CIRCLE_ARRAY[5][1]); MPath. CubicTo (// cubicTo iii r * CIRCLE_ARRAY[6][0], r * CIRCLE_ARRAY[6][1], r * CIRCLE_ARRAY[7][0], r * CIRCLE_ARRAY[7][1], r * CIRCLE_ARRAY[8][0], r * (runNum) * CIRCLE_ARRAY[8][1]); / / < -- move me try mPath. CubicTo (/ / section 4 r * CIRCLE_ARRAY [9] [0], r * CIRCLE_ARRAY [9] [1], r * CIRCLE_ARRAY [10] [0]. r * CIRCLE_ARRAY[10][1], r * CIRCLE_ARRAY[11][0], r * CIRCLE_ARRAY[11][1]);Copy the code

You may say fat, thin can not

Move control point 2 in the first paragraph and control point 1 in the second paragraph up a little bit. There are only nine main points. Do you get them?

MPath. CubicTo (// cubicTo # r * CIRCLE_ARRAY[0][0], r * CIRCLE_ARRAY[0][1], r * CIRCLE_ARRAY[1][0], R * CIRCLE_ARRAY [1] [1] - (0.3 f) (1 - runNum) * * r, r * CIRCLE_ARRAY [2] [0], r * CIRCLE_ARRAY [2] [1]). MPath. CubicTo (// cubicTo * r * CIRCLE_ARRAY[3][0], r * CIRCLE_ARRAY[3][1] - ((1-runnum) * 0.3f) * r, r * CIRCLE_ARRAY[4][0], r * CIRCLE_ARRAY[4][1], r * CIRCLE_ARRAY[5][0], r * CIRCLE_ARRAY[5][1]); MPath. CubicTo (// cubicTo iii r * CIRCLE_ARRAY[6][0], r * CIRCLE_ARRAY[6][1], r * CIRCLE_ARRAY[7][0], r * CIRCLE_ARRAY[7][1], R * CIRCLE_ARRAY [8] [0], r * CIRCLE_ARRAY [8] [1] + (0.6 f) (1 - runNum) * * r); MPath. CubicTo (// cubicTo d r * CIRCLE_ARRAY[9][0], r * CIRCLE_ARRAY[9][1], r * CIRCLE_ARRAY[10][0], r * CIRCLE_ARRAY[10][1], r * CIRCLE_ARRAY[11][0], r * CIRCLE_ARRAY[11][1]);Copy the code

4. What if you want to get flat/wide?

The lower three points shift together

MPath. CubicTo (// cubicTo # r * CIRCLE_ARRAY[0][0], r * CIRCLE_ARRAY[0][1], r * CIRCLE_ARRAY[1][0], R * CIRCLE_ARRAY[1][1]+ (1-runnum) * 0.6f * r, r * CIRCLE_ARRAY[2][0], R * CIRCLE_ARRAY [2] [1] + (1 - runNum) * 0.6 f * r); MPath. CubicTo (// cubicTo + r * CIRCLE_ARRAY[3][0], r * CIRCLE_ARRAY[3][1]+ (1-runnum) * 0.6f * r, r * CIRCLE_ARRAY[4][0], r * CIRCLE_ARRAY[4][1], r * CIRCLE_ARRAY[5][0], r * CIRCLE_ARRAY[5][1]); MPath. CubicTo (// cubicTo iii r * CIRCLE_ARRAY[6][0], r * CIRCLE_ARRAY[6][1], r * CIRCLE_ARRAY[7][0], r * CIRCLE_ARRAY[7][1], r * CIRCLE_ARRAY[8][0], r * CIRCLE_ARRAY[8][1]) ; MPath. CubicTo (// cubicTo d r * CIRCLE_ARRAY[9][0], r * CIRCLE_ARRAY[9][1], r * CIRCLE_ARRAY[10][0], r * CIRCLE_ARRAY[10][1], r * CIRCLE_ARRAY[11][0], r * CIRCLE_ARRAY[11][1]);Copy the code

Let’s make the bottom a little bit sharper

MPath. CubicTo (// cubicTo # r * CIRCLE_ARRAY[0][0], r * CIRCLE_ARRAY[0][1], r * CIRCLE_ARRAY[1][0], R * CIRCLE_ARRAY[1][1]+ (1-runnum) * 0.6f * r - ((1-runnum) * 0.3f) * r, r * CIRCLE_ARRAY[2][0], R * CIRCLE_ARRAY [2] [1] + (1 - runNum) * 0.6 f * r); MPath. CubicTo (// 三 段 r * CIRCLE_ARRAY[3][0], R * CIRCLE_ARRAY[3][1]+ (1-runnum) * 0.6f * r - ((1-runnum) * 0.3f) * r, r * CIRCLE_ARRAY[4][0], r * CIRCLE_ARRAY[4][1], r * CIRCLE_ARRAY[5][0], r * CIRCLE_ARRAY[5][1]); MPath. CubicTo (// cubicTo iii r * CIRCLE_ARRAY[6][0], r * CIRCLE_ARRAY[6][1], r * CIRCLE_ARRAY[7][0], r * CIRCLE_ARRAY[7][1], r * CIRCLE_ARRAY[8][0], r * CIRCLE_ARRAY[8][1]) ; MPath. CubicTo (// cubicTo d r * CIRCLE_ARRAY[9][0], r * CIRCLE_ARRAY[9][1], r * CIRCLE_ARRAY[10][0], r * CIRCLE_ARRAY[10][1], r * CIRCLE_ARRAY[11][0], r * CIRCLE_ARRAY[11][1]);Copy the code
5. Control point length variation: The Origin of Ufos…

Change coordinates to lengthen control point 2 of line 1 and control point 1 of line 2

MPath. CubicTo (// cubicTo # r * CIRCLE_ARRAY[0][0], r * CIRCLE_ARRAY[0][1], r * CIRCLE_ARRAY[1][0] - (1-runnum) * 4f * r, r * CIRCLE_ARRAY[1][1], r * CIRCLE_ARRAY[2][0], r * CIRCLE_ARRAY[2][1]); MPath. CubicTo (// cubicTo # r * CIRCLE_ARRAY[3][0]+ (1-runnum) * 4f * r, r * CIRCLE_ARRAY[3][1], r * CIRCLE_ARRAY[4][0], r * CIRCLE_ARRAY[4][1], r * CIRCLE_ARRAY[5][0], r * CIRCLE_ARRAY[5][1]); MPath. CubicTo (// cubicTo iii r * CIRCLE_ARRAY[6][0], r * CIRCLE_ARRAY[6][1], r * CIRCLE_ARRAY[7][0], r * CIRCLE_ARRAY[7][1], r * CIRCLE_ARRAY[8][0], r * CIRCLE_ARRAY[8][1]); MPath. CubicTo (// cubicTo d r * CIRCLE_ARRAY[9][0], r * CIRCLE_ARRAY[9][1], r * CIRCLE_ARRAY[10][0], r * CIRCLE_ARRAY[10][1], r * CIRCLE_ARRAY[11][0], r * CIRCLE_ARRAY[11][1]);Copy the code
6. Touch event test

You can also use touch events to control these points without ValueAnimate.

MPath. CubicTo (// cubicTo # r * CIRCLE_ARRAY[0][0], r * CIRCLE_ARRAY[0][1], r * CIRCLE_ARRAY[1][1], r * CIRCLE_ARRAY[1][1], r * CIRCLE_ARRAY[2][0], r * CIRCLE_ARRAY[2][1]); MPath. CubicTo (// cubicTo ii r * CIRCLE_ARRAY[3][0], r * CIRCLE_ARRAY[3][1], r * CIRCLE_ARRAY[4][0], r * CIRCLE_ARRAY[4][1] r * CIRCLE_ARRAY[5][0] + src.x - 2*r, r * CIRCLE_ARRAY[5][1]+ src.y); MPath. CubicTo (// cubicTo iii r * CIRCLE_ARRAY[6][0], r * CIRCLE_ARRAY[6][1], r * CIRCLE_ARRAY[7][0], r * CIRCLE_ARRAY[7][1], r * CIRCLE_ARRAY[8][0], r * CIRCLE_ARRAY[8][1]); MPath. CubicTo (// cubicTo d r * CIRCLE_ARRAY[9][0], r * CIRCLE_ARRAY[9][1], r * CIRCLE_ARRAY[10][0], r * CIRCLE_ARRAY[10][1], r * CIRCLE_ARRAY[11][0], r * CIRCLE_ARRAY[11][1]);Copy the code

Ok, so that’s it, you can copy the source code to play with it, source file Lever2CubicView.java

In summary, the key to a Bezier curve is the three points where you can control the Bezier curve right in the palm of your hand. Besser cubic curve has a lot of operations against the sky, the ability is limited, we will study later if you need to play with the circular Besser, you can basically handle it. The Bezier curve is so deep that you can’t imagine it without it.


Postscript: Jie wen standard

1. Growth record and Errata of this paper
Program source code The date of note
V0.1 – making 2018-11-20 Android Drawing final battle bezier cubic curve
2. More about me
Pen name QQ WeChat hobby
Zhang Feng Jie te Li 1981462002 zdl1994328 language
My lot My Jane books I’m the nuggets Personal website
3. The statement

1—- This article is originally written by Zhang Fengjie, please note if reproduced

2—- welcome the majority of programming enthusiasts to communicate with each other 3—- personal ability is limited, if there is something wrong welcome to criticize and testify, must be humble to correct 4—- see here, I thank you here for your love and support