Android custom View advanced effects, magic beiser Curve

Source: Internet
Author: User

Android custom View advanced effects, magic beiser Curve

We have implemented a simple second-order besell curve that slides with your fingers, and a complex point that traverses the besell curve of all known points. After learning to use the besell curve, you can achieve QQ red dot sliding deletion, 360 dynamic ball, bulabulabula ~

What is the besell curve?

The bé-ier curve is a very important parameter curve in computer graphics. A higher dimension is called the besell curve. The besell triangle is a special example. In 1962, the beiser curve was widely published by French engineer Pierre béserz, who used the beiser curve to design the car's main body. The beiser curve was initially developed by Paul de Casteljau in 1959 using the de Casteljau algorithm and obtained by using a stable numerical method.

After reading the above description of the besell curve, I am still confused. Let's take an example.

Example linear besell Curve

For the numbers P0 and P1 at the specified point, the linear besell curve is just a straight line between two points. This line is shown below:

Bizell Curve

The path of the second beiser curve is traced by function B (t) of the given point P0, P1, and P2:

Cubic besell Curve

P0, P1, P2, and P3 point on a plane or in a three-dimensional space, a cubic besell curve is defined. The curve starts from P0 to P1 and starts from P2 to P3. It generally does not pass through P1 or P2. The formula is as follows:

N besell Curve

As a 3D creature, I am very interested. Here I will only give an example image. If you want to know more, please turn left to du Niang.

If you haven't read the above

When the API is set to 1, Android provides the description of the beiser curve, which is only hidden in the Path # quadTo () and Path # cubicTo () methods. One is the second-order beiser curve, one is the third-order besell curve. Of course, if you want to write a method by yourself, you can also follow the expression of besell above. However, it is generally unnecessary because Android has encapsulated second-and third-level functions for us at the native layer.

Customizes A BezierView from a second-level besell.

Initialize each parameter. You just need to scan it for 3 seconds.

Private Paint mPaint; private Path mPath; private Point startPoint; private Point endPoint; // The secondary Point private Point using Point; public BezierView (Context context) {this (context, null );} public BezierView (Context context, AttributeSet attrs) {this (context, attrs, 0);} public BezierView (Context context, AttributeSet attrs, int defStyleAttr) {super (context, attrs, defStyleAttr); init (context);} private void init (Context context) {mPaint = new Paint (); mPath = new Path (); startPoint = new Point (300,600 ); endPoint = new Point (900,600); destination Point = new Point (600,900); // anti-sawtooth mPaint. setAntiAlias (true); // anti-jitter mPaint. setDither (true );}

Draw second-order besell in onDraw

// Paint brush color mPaint. setColor (Color. BLACK); // pen width mPaint. setStrokeWidth (POINTWIDTH); // hollow mPaint. setStyle (Paint. style. STROKE); // reset the path mPath. reset (); // start point mPath. moveTo (startPoint. x, startPoint. y); // This is the mPath. quadTo (partition point. x, snapshot point. y, endPoint. x, endPoint. y); // specifies the painting path canvas. drawPath (mPath, mPaint); // draw the secondary canvas. drawPoint (vertex point. x, snapshot point. y, mPaint );

The above comments are clear and will not be repeated. In this example, besell can change with the sliding of his fingers. I will write onTouchEvent () in a single shot of durian ()!

    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:            case MotionEvent.ACTION_MOVE:                assistPoint.x = (int) event.getX();                assistPoint.y = (int) event.getY();                Log.i(TAG, "assistPoint.x = " + assistPoint.x);                Log.i(TAG, "assistPoint.Y = " + assistPoint.y);                invalidate();                break;        }        return true;    }

Finally, add our custom BezierView to the layout file. Now a simple second-order besell curve is complete. Let's assume that, in the downward pull process, a "little Superman" is added to the curve, and 360 dynamic cleanup is coming out? If you are interested, you can expand it on your own.

An example of ending the weather forecast curve with a third-level besell

(Figure 1)

(Figure 2)

Overview

For the desired effect, the second-order and third-order besels must be used together. The specific manifestation is that the first and last curves are second-order besell, and the N in the middle are all third-order besell curves.

Ideas

Calculate the midpoint (P4, P5) of the adjacent vertex Based on the adjacent vertex (P1, P2, P3), and then calculate the midpoint (P6) of the adjacent midpoint ). Then, the line segments (P4, P6, P5) are translated to the P2. Then, the coordinates of (P7, P8) are calculated based on the coordinates of (P4, P6, P5, P2. Finally, draw a third-order besell Curve Based on control points such as P7 and P8.

Point and line explanation black point: the point to pass, for example, temperature blue point: two black points constitute the midpoint yellow point of a line segment: Two blue points constitute the midpoint gray point of a line segment: the red line of the beiser curve control point: The line chart of the Black Point black line: The beiser curve of the black point. It is also our final effect statement.

For ease of explanation and understanding. This article uses Figure 1 as an example. BezierView coordinates are dynamically generated based on the screen. To achieve the effect of Figure 2, you only need to modify the initial coordinates without making significant changes to the Code.

So, let's get started! Initialization parameters
Private static final String TAG = "bizr"; private static final int LINEWIDTH = 5; private static final int POINTWIDTH = 10; private Context mContext; /** vertex set to be traversed */private List
  
   
MPoints = new ArrayList <> ();/** midpoint Set */private List
   
    
MMidPoints = new ArrayList <> ();/** midpoint set of the midpoint */private List
    
     
MMidMidPoints = new ArrayList <> ();/** point set after moving (Control Point) */private List
     
      
MControlPoints = new ArrayList <> (); private int mScreenWidth; private int mScreenHeight; private void init (Context context) {mPaint = new Paint (); mPath = new Path (); // anti-sawtooth mPaint. setAntiAlias (true); // anti-jitter mPaint. setDither (true); mContext = context; getScreenParams (); initPoints (); initMidPoints (this. mPoints); initMidMidPoints (this. mMidPoints); initControlPoints (this. mPoints, this. mMidPoints, this. mMidMidPoints );}
     
    
   
  

The first function gets the screen width and height. Then, the vertex, midpoint, and control point of the initial vertex, midpoint, and midpoint are initialized. We follow up one by one. The first is the initial point.

/** Add the vertex to be crossed */private void initPoints () {int pointWidthSpace = mScreenWidth/5; int pointHeightSpace = 100; for (int I = 0; I <5; I ++) {Point point Point; // if (I % 2! = 0) {point = new Point (int) (pointWidthSpace * (I + 0.5), mScreenHeight/2-pointHeightSpace);} else {point = new Point (int) (pointWidthSpace * (I + 0.5), mScreenHeight/2);} mPoints. add (point );}}

Here, we cyclically create one, one, two, and five points, and add them to the List. In mPoints. As shown in figure 1 to figure 2 above, you only need to modify the initial vertex here.

/** Initialize the midpoint Set */private void initMidPoints (List
  
   
Points) {for (int I = 0; I <points. size (); I ++) {Point midPoint = null; if (I = points. size ()-1) {return;} else {midPoint = new Point (points. get (I ). x + points. get (I + 1 ). x)/2, (points. get (I ). y + points. get (I + 1 ). y)/2);} mMidPoints. add (midPoint) ;}}/** initialize the midPoint set of the midPoint */private void initMidMidPoints (List
   
    
MidPoints) {for (int I = 0; I <midPoints. size (); I ++) {Point midMidPoint = null; if (I = midPoints. size ()-1) {return;} else {midMidPoint = new Point (midPoints. get (I ). x + midPoints. get (I + 1 ). x)/2, (midPoints. get (I ). y + midPoints. get (I + 1 ). y)/2);} mMidMidPoints. add (midMidPoint );}}
   
  

Here, we can calculate the Point Set and the point set. There is nothing to say about primary school mathematics. The only thing to note is the difference in their quantity.

/** Initialize the Control Point Set */private void initControlPoints (List
  
   
Points, List
   
    
MidPoints, List
    
     
MidMidPoints) {for (int I = 0; I <points. size (); I ++) {if (I = 0 | I = points. size ()-1) {continue;} else {Point before = new Point (); Point after = new Point (); before. x = points. get (I ). x-midMidPoints. get (I-1 ). x + midPoints. get (I-1 ). x; before. y = points. get (I ). y-midMidPoints. get (I-1 ). y + midPoints. get (I-1 ). y; after. x = points. get (I ). x-midMidPoints. get (I-1 ). x + midPoints. get (I ). x; after. y = points. get (I ). y-midMidPoints. get (I-1 ). y + midPoints. get (I ). y; mControlPoints. add (before); mControlPoints. add (after );}}}
    
   
  

Pay attention to the calculation process of this method. Take Figure 1 (P2, P4, P6, P8) as an example. Currently, the coordinates of P2, P4, and P6 are known. Since the (P8, P2) line segments are translated from the (P4, P6) line segments, the following conclusions can be obtained: P2-P6 = P8-P4. That is, P8 = P2-P6 + P4. The rest are the same.

Draw secondary points and compare line charts
@ Override protected void onDraw (Canvas canvas) {super. onDraw (canvas ); //************************************** ******************** // ***************** besell advanced-Qu slide through known points **********************//************ **************************************** * ****** // draw the original vertex drawPoints (canvas ); // draw the line drawCrossPointsBrokenLine (canvas) that crosses the original vertex; // draw the middle vertex drawMidPoints (canvas); // draw the middle vertex drawMidMidPoints (canvas) of the intermediate vertex ); // draw the control point drawControlPoints (canvas); // draw the béserx curve drawbeier (canvas );}

We can see that we have drawn a series of auxiliary points before drawing the besell curve, as well as a line chart for comparison with the besell curve. Result 1. The coordinates of the auxiliary points are all obtained, and the basic painting is relatively simple. If you have the ability, you can skip the following section and directly enterdrawBezier(canvas)Method. For basic painting, only code is pasted here. If you have any questions, you can comment or send a private message.

/** Original point of painting */private void drawPoints (Canvas canvas) {mPaint. setStrokeWidth (POINTWIDTH); for (int I = 0; I <mPoints. size (); I ++) {canvas. drawPoint (mPoints. get (I ). x, mPoints. get (I ). y, mPaint) ;}}/ ** draw the line through the original point */private void drawCrossPointsBrokenLine (Canvas canvas) {mPaint. setStrokeWidth (LINEWIDTH); mPaint. setColor (Color. RED); // reset the path mPath. reset (); // draw the line mPath that crosses the original point. moveTo (mPoints. get (0 ). x, mPoints. get (0 ). y); for (int I = 0; I <mPoints. size (); I ++) {mPath. lineTo (mPoints. get (I ). x, mPoints. get (I ). y);} canvas. drawPath (mPath, mPaint);}/** draw center point */private void drawMidPoints (Canvas canvas Canvas) {mPaint. setStrokeWidth (POINTWIDTH); mPaint. setColor (Color. BLUE); for (int I = 0; I <mMidPoints. size (); I ++) {canvas. drawPoint (mMidPoints. get (I ). x, mMidPoints. get (I ). y, mPaint) ;}}/ ** draw the center point of the center */private void drawMidMidPoints (Canvas canvas Canvas) {mPaint. setColor (Color. YELLOW); for (int I = 0; I <mMidMidPoints. size (); I ++) {canvas. drawPoint (mMidMidPoints. get (I ). x, mMidMidPoints. get (I ). y, mPaint) ;}}/** painting Control Point */private void drawControlPoints (Canvas canvas) {mPaint. setColor (Color. GRAY); // draw a control point for (int I = 0; I <mControlPoints. size (); I ++) {canvas. drawPoint (mControlPoints. get (I ). x, mControlPoints. get (I ). y, mPaint );}}
Draw the besell Curve
/** Draw the Bessert curve */private void drawbezr (Canvas canvas) {mPaint. setStrokeWidth (LINEWIDTH); mPaint. setColor (Color. BLACK); // reset the path mPath. reset (); for (int I = 0; I <mPoints. size (); I ++) {if (I = 0) {// The first entry is a second-order besell mPath. moveTo (mPoints. get (I ). x, mPoints. get (I ). y); // start point mPath. quadTo (mControlPoints. get (I ). x, mControlPoints. get (I ). y, // Control Point mPoints. get (I + 1 ). x, mPoints. get (I + 1 ). y);} else if (I <mPoints. size ()-2) {// Level 3 bessermpath. cubicTo (mControlPoints. get (2 * i-1 ). x, mControlPoints. get (2 * i-1 ). y, // Control Point mControlPoints. get (2 * I ). x, mControlPoints. get (2 * I ). y, // Control Point mPoints. get (I + 1 ). x, mPoints. get (I + 1 ). y); // end} else if (I = mPoints. size ()-2) {// The last one is a second-order bessermpath. moveTo (mPoints. get (I ). x, mPoints. get (I ). y); // start point mPath. quadTo (mControlPoints. get (mControlPoints. size ()-1 ). x, mControlPoints. get (mControlPoints. size ()-1 ). y, mPoints. get (I + 1 ). x, mPoints. get (I + 1 ). y); // end} canvas. drawPath (mPath, mPaint );}

The comments are too detailed and there is nothing to write. However, you need to pay attention to the conditions in the judgment and be sure to understand the judgment of the start and end points. Otherwise, you may be given an ArrayIndexOutOfBoundsException.

End

The Bessert curve can achieve a lot of brilliant results, but the difficulty is not the Bessert, but the good idea.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.