免费高清特黄a大片,九一h片在线免费看,a免费国产一级特黄aa大,国产精品国产主播在线观看,成人精品一区久久久久,一级特黄aa大片,俄罗斯无遮挡一级毛片

分享

兩張圖教你使用二三階貝塞爾曲線

 小橋流水ytff06 2018-03-20

兩張圖教你使用二三階貝塞爾曲線 - CSDN博客 http://blog.csdn.net/DylanZhuang/article/details/51896564

Bézier curve(貝塞爾曲線)是應(yīng)用于二維圖形應(yīng)用程序的數(shù)學(xué)曲線。 曲線定義:起始點、終止點(也稱錨點)、控制點。通過調(diào)整控制點,貝塞爾曲線的形狀會發(fā)生化。 1962年,法國數(shù)學(xué)家Pierre Bézier第一個研究了這種矢量繪制曲線的方法,并給出了詳細(xì)的計算公式,因此按照這樣的公式繪制出來的曲線就用他的姓氏來命名,稱為貝塞爾曲線。

線性公式

給定點p0、p1,線性貝塞爾曲線只是一條兩點之間的直線,公式如下:

二次方公式

二次方貝塞爾曲線的路徑由給定點p0、p1、p2的函數(shù)B(t),公式如下:


三次方公式

p0、p1、p2、p3四個點在平面或在三維空間定義了三次貝塞爾曲線。曲線起始于p0走向p1,并從p2的方向來到p3.一般不會經(jīng)過p1或者p2;這兩點只是在那里提供了方向資訊。p0和p1之間的間距,決定了曲線在轉(zhuǎn)而趨進(jìn)p3之前,走向p2方向的“長度有多長”,公式如下:

上面這段是摘自百度百科,由上面的動態(tài)圖可以看出,一階貝塞爾曲線是由兩點控制的一條直線,二階貝塞爾曲線是由一個控制點控制的曲線,三階貝塞爾曲線是由兩個控制點控制的曲線,至于三階以上的不做研究

下面看一下二階貝塞爾曲線運行的效果圖:


設(shè)置二階貝塞爾曲線的方法如下

moveTo(float x, float y) 其中x、y坐標(biāo)代表圖中曲線靠左邊起點的坐標(biāo)位置

quadTo(float x1, float y1, float x2, float y2) 其中x1、y1坐標(biāo)代表圖中移動點的坐標(biāo),也就是我們所說的二階貝塞爾曲線的控制點坐標(biāo);x2、y2坐標(biāo)代表圖中曲線靠右邊終點的坐標(biāo)位置

首先我們要重寫view的onTouchEvent的事件,并對該事件進(jìn)行攔截,也就是返回值為true,代碼如下:

  1. @Override    
  2.  public boolean onTouchEvent(MotionEvent event) {    
  3.      switch (event.getAction()) {    
  4.          case MotionEvent.ACTION_DOWN:    
  5.              break;    
  6.          case MotionEvent.ACTION_MOVE:    
  7.              int moveX = (int) (event.getX());    
  8.              int moveY = (int) (event.getY());    
  9.              mControlPoint.x = moveX;    
  10.              mControlPoint.y = moveY;    
  11.              invalidate();    
  12.              break;    
  13.      }    
  14.      return true;    
  15.  }  

在move事件中,獲取到控制點的坐標(biāo),并在onDraw方法中進(jìn)行路徑的繪制,代碼如下:

初始化起始點:

  1. mPaint = new Paint();    
  2. mPaint.setStyle(Paint.Style.STROKE);    
  3.     
  4. DisplayMetrics displayMetrics = getResources().getDisplayMetrics();    
  5. mWidth = displayMetrics.widthPixels;    
  6. mHeight = displayMetrics.heightPixels;    
  7.     
  8. mStartPoint.set(100, mHeight / 2);    
  9. mEndPoint.set(mWidth - 100, mHeight / 2);    
  10. mControlPoint.set(mWidth / 2, 100);  

進(jìn)行繪制:

  1. private void drawQuadraticBezier(Canvas canvas) {    
  2.     mPaint.setColor(Color.RED);    
  3.     mPaint.setStrokeWidth(20);    
  4.     mPaint.setStyle(Paint.Style.STROKE);    
  5.     canvas.drawCircle(mControlPoint.x, mControlPoint.y, 10, mPaint);    
  6.     
  7.     mPaint.setStrokeWidth(10);    
  8.     mPaint.setStyle(Paint.Style.FILL);    
  9.     float[] lines = {mStartPoint.x, mStartPoint.y, mControlPoint.x, mControlPoint.y,    
  10.             mControlPoint.x, mControlPoint.y, mEndPoint.x, mEndPoint.y,    
  11.             mEndPoint.x, mEndPoint.y, mStartPoint.x, mStartPoint.y};    
  12.     canvas.drawLines(lines, mPaint);    
  13.     
  14.     mPaint.setColor(Color.GREEN);    
  15.     mPaint.setStyle(Paint.Style.STROKE);    
  16.     Path path = new Path();    
  17.     path.moveTo(mStartPoint.x, mStartPoint.y);    
  18.     path.quadTo(mControlPoint.x, mControlPoint.y, mEndPoint.x, mEndPoint.y);    
  19.     canvas.drawPath(path, mPaint);    
  20. }  

二階貝塞爾曲線到這里已經(jīng)介紹完了,接下來介紹下三階貝塞爾曲線,先看下效果圖:

設(shè)置二階貝塞爾曲線的方法如下

moveTo(float x, float y) 其中x、y坐標(biāo)代表圖中在圓周上靠左邊起點的坐標(biāo)位置

cubicTo(float x1, float y1, float x2, float y2, float x3, float y3) 其中x1、y1坐標(biāo)代表圖中左上角移動點的坐標(biāo),x2、y2坐標(biāo)代表圖中右上角移動點的坐標(biāo),x1、y1和x2、y2也就是我們所說的三階貝塞爾曲線的控制點坐標(biāo);x3、y3坐標(biāo)代表圖中在圓周上靠右邊終點的坐標(biāo)位置

首先我們要重寫view的onTouchEvent的事件,并對該事件進(jìn)行攔截,也就是返回值為true,代碼如下:

  1. @Override    
  2.   public boolean onTouchEvent(MotionEvent event) {    
  3.       switch (event.getAction()) {    
  4.           case MotionEvent.ACTION_DOWN:    
  5.               break;    
  6.           case MotionEvent.ACTION_MOVE:    
  7.               int moveX = (int) (event.getX());    
  8.               int moveY = (int) (event.getY());    
  9.     
  10.               int distanceX = Math.abs(mControlPoint.x - moveX);    
  11.               int distanceY = Math.abs(mControlPoint.y - moveY);    
  12.     
  13.               int distanceX1 = Math.abs(mControlPoint1.x - moveX);    
  14.               int distanceY1 = Math.abs(mControlPoint1.y - moveY);    
  15.               if (distanceX < 50 && distanceY < 50) {    
  16.                   mControlPoint.x = moveX;    
  17.                   mControlPoint.y = moveY;    
  18.               } else if (distanceX1 < 50 && distanceY1 < 50) {    
  19.                   mControlPoint1.x = moveX;    
  20.                   mControlPoint1.y = moveY;    
  21.               }    
  22.               invalidate();    
  23.               break;    
  24.       }    
  25.       return true;    
  26.   }    

在move事件中,判斷當(dāng)前觸摸的是哪個控制點,并對該控制點進(jìn)行賦值,繪制代碼如下:初始化數(shù)據(jù):

  1. mBloomCenterPoint.set(mWidth / 2, mHeight / 2);    
  2. mStartPoint.set(mWidth / 2, mHeight / 2);    
  3. mEndPoint.set(mWidth / 2, mHeight / 2);    
  4. mControlPoint.set(mWidth / 2 - 200, 100);    
  5. mControlPoint1.set(mWidth / 2 + 200, 100);   

開始繪制:

  1. private void drawCubicBezier(Canvas canvas) {    
  2.         Point topPoint = new Point(mBloomCenterPoint.x, mBloomCenterPoint.y - mRadius);    
  3.         float angle1 = (mBloomCenterPoint.x - mControlPoint.x) * 1.0f / (mBloomCenterPoint.y - mControlPoint.y);    
  4.         float angle2 = (mBloomCenterPoint.x - mControlPoint1.x) * 1.0f / (mBloomCenterPoint.y - mControlPoint1.y);    
  5.     
  6.         boolean isBig1 = false;    
  7.         boolean isBig2 = false;    
  8.         if (mControlPoint.y > mBloomCenterPoint.y) {    
  9.             isBig1 = true;    
  10.         }    
  11.         if (mControlPoint1.y > mBloomCenterPoint.y) {    
  12.             isBig2 = true;    
  13.         }    
  14.         //獲取三階貝塞爾曲線的起始點的值    
  15.         mStartPoint = getFixPoint(topPoint, angle1, isBig1);    
  16.         mEndPoint = getFixPoint(topPoint, angle2, isBig2);    
  17.     
  18.         mPaint.setColor(Color.RED);    
  19.         mPaint.setStrokeWidth(1);    
  20.         mPaint.setStyle(Paint.Style.STROKE);    
  21.         canvas.drawCircle(mControlPoint.x, mControlPoint.y, 10, mPaint);    
  22.         canvas.drawCircle(mControlPoint1.x, mControlPoint1.y, 10, mPaint);    
  23.         canvas.drawCircle(mBloomCenterPoint.x, mBloomCenterPoint.y, mRadius, mPaint);    
  24.     
  25.         mPaint.setStrokeWidth(10);    
  26.         mPaint.setStyle(Paint.Style.FILL);    
  27.         float[] lines = {mStartPoint.x, mStartPoint.y, mControlPoint.x, mControlPoint.y,    
  28.                 mControlPoint.x, mControlPoint.y, mControlPoint1.x, mControlPoint1.y,    
  29.                 mControlPoint1.x, mControlPoint1.y, mEndPoint.x, mEndPoint.y,    
  30.                 mEndPoint.x, mEndPoint.y, mStartPoint.x, mStartPoint.y};    
  31.         canvas.drawLines(lines, mPaint);    
  32.     
  33.         mPaint.setStrokeWidth(10);    
  34.         mPaint.setColor(Color.GREEN);    
  35.         mPaint.setStyle(Paint.Style.FILL);    
  36.         Path path = new Path();    
  37.         path.moveTo(mStartPoint.x, mStartPoint.y);    
  38.         path.cubicTo(mControlPoint.x, mControlPoint.y, mControlPoint1.x, mControlPoint1.y, mEndPoint.x, mEndPoint.y);    
  39.         canvas.drawPath(path, mPaint);    
  40.     }    

  1. private Point getFixPoint(Point topPoint, float angle, boolean isBig) {    
  2.     double radian = Math.atan(angle);    
  3.     if (isBig) {    
  4.         radian += Math.PI;    
  5.     }    
  6.     double sin = Math.sin(radian);    
  7.     double cos = Math.cos(radian);    
  8.     int x = (int) (topPoint.x - mRadius * sin);    
  9.     int y = (int) (topPoint.y + mRadius * (1 - cos));    
  10.     
  11.     Point point = new Point(x, y);    
  12.     return point;    
  13. }    

高級進(jìn)階像360安全衛(wèi)士清理內(nèi)存的動態(tài)效果大家應(yīng)該都不陌生吧,我們現(xiàn)在用二階貝塞爾曲線實現(xiàn)這樣的效果,先上效果圖:

首先我們初始化數(shù)據(jù),代碼如下:

  1. private void init() {    
  2.     DisplayMetrics displayMetrics = getResources().getDisplayMetrics();    
  3.     mScreenWidth = displayMetrics.widthPixels;    
  4.     mScreenHeight = displayMetrics.heightPixels;    
  5.     
  6.     int height = mScreenHeight * 7 / 10;    
  7.     mStartPoint.set(mScreenWidth / 10, height);    
  8.     mEndPoint.set(mScreenWidth * 9 / 10, height);    
  9.     
  10.     mRadius = 100;    
  11. }    

然后重寫onTouchEvent事件,不斷的重繪紅色的球和綠色的曲線,當(dāng)只有在球與線接觸時,才進(jìn)行二階貝塞爾曲線的繪制,touch事件的代碼如下:

  1. @Override    
  2. public boolean onTouchEvent(MotionEvent event) {    
  3.     switch (event.getAction()) {    
  4.         case MotionEvent.ACTION_MOVE:    
  5.             int moveX = (int) (event.getX());    
  6.             int moveY = (int) (event.getY());    
  7.     
  8.             mControlPoint.x = moveX;    
  9.             mControlPoint.y = moveY;    
  10.             invalidate();    
  11.             break;    
  12.         case MotionEvent.ACTION_UP:    
  13.             int x = mControlPoint.x;    
  14.             int y = mControlPoint.y;    
  15.             if (y > mStartPoint.y && x > mScreenWidth * 2 / 5    
  16.                     && x < mScreenWidth * 3 / 5) {    
  17.                 startAnim();    
  18.             }    
  19.             break;    
  20.     }    
  21.     return true;    
  22. }    

當(dāng)執(zhí)行ACTION_UP事件時,判斷此時控制點是否進(jìn)行了二階變換,如果是,則進(jìn)行動畫的繪制,動畫效果的代碼如下:

  1. private void startAnim() {    
  2.     ValueAnimator valueAnimator = ValueAnimator.ofInt(mControlPoint.y, -10);    
  3.     valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {    
  4.         @Override    
  5.         public void onAnimationUpdate(ValueAnimator animation) {    
  6.             mControlPoint.y = (int) animation.getAnimatedValue();    
  7.             invalidate();    
  8.         }    
  9.     });    
  10.     valueAnimator.setDuration(1000);    
  11.     valueAnimator.start();    
  12. }    

下面看下球跟線接觸時,視圖是怎么繪制的,代碼如下:

  1. @Override    
  2.  protected void onDraw(Canvas canvas) {    
  3.      super.onDraw(canvas);    
  4.     
  5.      Paint paint = new Paint();    
  6.      paint.setStrokeWidth(10);    
  7.      paint.setStyle(Paint.Style.STROKE);    
  8.      paint.setColor(Color.GREEN);    
  9.     
  10.      int x = mControlPoint.x;    
  11.      int y = mControlPoint.y;    
  12.      int height = mStartPoint.y;    
  13.      if (y > mStartPoint.y && x > mScreenWidth * 2 / 5    
  14.              && x < mScreenWidth * 3 / 5) {    
  15.          height = y + y - mStartPoint.y;    
  16.      }    
  17.     
  18.      Path path = new Path();    
  19.      path.moveTo(mStartPoint.x, mStartPoint.y);    
  20.      path.quadTo(mScreenWidth / 2, height, mEndPoint.x, mEndPoint.y);    
  21.      canvas.drawPath(path, paint);    
  22.     
  23.      paint.setStyle(Paint.Style.FILL);    
  24.      paint.setColor(Color.RED);    
  25.      canvas.drawCircle(x, y - mRadius, mRadius, paint);    
  26.  }    

代碼中控制點高度的計算,是通過二階變換公式相減得到的,到目前為止,該過程的繪制代碼已全部列出。在進(jìn)行三階貝塞爾曲線變換的時候,綠色部分有點像個花瓣,下面我們用三階貝塞爾曲線,繪制一朵花,效果圖如下:


我們先用進(jìn)行下數(shù)據(jù)的初始化操作,定義些常量,代碼如下:

  1. public interface BloomOption {    
  2.     //用于控制產(chǎn)生隨機(jī)花瓣個數(shù)范圍    
  3.     int minPetalCount = 8;    
  4.     int maxPetalCount = 12;    
  5.     //用于控制產(chǎn)生延長線倍數(shù)范圍    
  6.     float minPetalStretch = 2f;    
  7.     float maxPetalStretch = 3.5f;    
  8.     //用于控制產(chǎn)生花朵半徑隨機(jī)數(shù)范圍    
  9.     int minBloomRadius = 100;    
  10.     int maxBloomRadius = 300;    
  11. }    

并進(jìn)行數(shù)據(jù)的一些初始化操作:

  1. private void init() {    
  2.     DisplayMetrics displayMetrics = getResources().getDisplayMetrics();    
  3.     int screenWidth = displayMetrics.widthPixels;    
  4.     int screenHeight = displayMetrics.heightPixels;    
  5.     mBloomCenterPoint.set(screenWidth / 2,  screenHeight / 2 - 200);    
  6.     petals = new ArrayList<>();    
  7.     initPetalData();    
  8. }  
  1. private void initPetalData() {    
  2.      int petalCount = RandomUtil.randomInt(minPetalCount, maxPetalCount);    
  3.      //每個花瓣應(yīng)占用的角度    
  4.      float angle = 360f / petalCount;    
  5.      int startAngle = RandomUtil.randomInt(0, 90);    
  6.     
  7.      for (int i = 0; i < petalCount; i++) {    
  8.          //隨機(jī)產(chǎn)生第一個控制點的拉伸倍數(shù)    
  9.          float stretchA = RandomUtil.random(minPetalStretch, maxPetalStretch);    
  10.          //隨機(jī)產(chǎn)生第二個控制地的拉伸倍數(shù)    
  11.          float stretchB = RandomUtil.random(minPetalStretch, maxPetalStretch);    
  12.          //計算每個花瓣的起始角度    
  13.          int beginAngle = startAngle + (int) (i * angle);    
  14.     
  15.          PetalView petal = new PetalView(stretchA, stretchB, beginAngle, angle);    
  16.          petals.add(petal);    
  17.      }    
  18.  }    

下面進(jìn)行綠色線條的繪制,代碼如下:

  1. private void drawStem(Canvas canvas) {    
  2.     Paint paint = new Paint();    
  3.     paint.setStrokeWidth(10);    
  4.     paint.setColor(Color.GREEN);    
  5.     paint.setStyle(Paint.Style.STROKE);    
  6.     
  7.     Path path = new Path();    
  8.     path.moveTo(mBloomCenterPoint.x, mBloomCenterPoint.y);    
  9.     path.quadTo(mBloomCenterPoint.x + 50, mBloomCenterPoint.y + 200, mBloomCenterPoint.x - 50, mBloomCenterPoint.y + 600);    
  10.     canvas.drawPath(path, paint);    
  11. }    

下面進(jìn)行花的繪制,代碼如下:onDraw方法:

  1. int radius = RandomUtil.randomInt(minBloomRadius, maxBloomRadius);    
  2. int size = petals.size();    
  3. MyPoint point = new MyPoint(mBloomCenterPoint.x, mBloomCenterPoint.y);    
  4. for (int i = 0; i < size; i++) {    
  5.     PetalView petal = petals.get(i);    
  6.     if (petal != null) {    
  7.         petal.render(point, radius, canvas);    
  8.     }    
  9. }    

PetalView.java:

  1. public class PetalView {    
  2.     private static final String TAG = "PetalView";    
  3.     
  4.     private float stretchA;//第一個控制點延長線倍數(shù)    
  5.     private float stretchB;//第二個控制點延長線倍數(shù)    
  6.     private float startAngle;//起始旋轉(zhuǎn)角,用于確定第一個端點    
  7.     private float angle;//兩條線之間夾角,由起始旋轉(zhuǎn)角和夾角可以確定第二個端點    
  8.     private int radius = 100;//花芯的半徑    
  9.     private Path path = new Path();//用于保存三次貝塞爾曲線    
  10.     private Paint paint = new Paint();    
  11.     
  12.     public PetalView(float stretchA, float stretchB, float startAngle, float angle) {    
  13.         this.stretchA = stretchA;    
  14.         this.stretchB = stretchB;    
  15.         this.startAngle = startAngle;    
  16.         this.angle = angle;    
  17.         paint.setColor(Color.RED);    
  18.     }    
  19.     
  20.     public void render(MyPoint p, int radius, Canvas canvas) {    
  21.         if (this.radius <= radius) {    
  22.             this.radius += 25;    
  23.         }    
  24.         draw(p, canvas);    
  25.     }    
  26.     
  27.     private void draw(MyPoint p, Canvas canvas) {    
  28.         path = new Path();    
  29.         //將向量(0,radius)旋轉(zhuǎn)起始角度,第一個控制點根據(jù)這個旋轉(zhuǎn)后的向量計算    
  30.         MyPoint t = new MyPoint(0, this.radius).rotate(RandomUtil.degrad(this.startAngle));    
  31.         //第一個端點,為了保證圓心不會隨著radius增大而變大這里固定為3    
  32.         MyPoint v1 = new MyPoint(0, 3).rotate(RandomUtil.degrad(this.startAngle));    
  33.         //第二個端點    
  34.         MyPoint v2 = t.clone().rotate(RandomUtil.degrad(this.angle));    
  35.         //延長線,分別確定兩個控制點    
  36.         MyPoint v3 = t.clone().mult(this.stretchA);    
  37.         MyPoint v4 = v2.clone().mult(this.stretchB);    
  38.         //由于圓心在p點,因此,每個點要加圓心坐標(biāo)點    
  39.         v1.add(p);    
  40.         v2.add(p);    
  41.         v3.add(p);    
  42.         v4.add(p);    
  43.     
  44.         path.moveTo(v1.x, v1.y);    
  45.         //參數(shù)分別是:第一個控制點,第二個控制點,終點    
  46.         path.cubicTo(v3.x, v3.y, v4.x, v4.y, v2.x, v2.y);    
  47.         canvas.drawPath(path, paint);    
  48.     }    
  49. }    

MyPoint.java:

  1. public class MyPoint {    
  2.     public int x;    
  3.     public int y;    
  4.     
  5.     public MyPoint() {    
  6.     }    
  7.     
  8.     public MyPoint(int x, int y) {    
  9.         this.x = x;    
  10.         this.y = y;    
  11.     }    
  12.     
  13.     //旋轉(zhuǎn)    
  14.     public MyPoint rotate(float theta) {    
  15.         int x = this.x;    
  16.         int y = this.y;    
  17.         this.x = (int) (Math.cos(theta) * x - Math.sin(theta) * y);    
  18.         this.y = (int) (Math.sin(theta) * x + Math.cos(theta) * y);    
  19.         return this;    
  20.     }    
  21.     
  22.     //乘以一個常數(shù)    
  23.     public MyPoint mult(float f) {    
  24.         this.x *= f;    
  25.         this.y *= f;    
  26.         return this;    
  27.     }    
  28.     
  29.     //復(fù)制    
  30.     public MyPoint clone() {    
  31.         return new MyPoint(this.x, this.y);    
  32.     }    
  33.     
  34.     //向量相減    
  35.     public MyPoint subtract(MyPoint p) {    
  36.         this.x -= p.x;    
  37.         this.y -= p.y;    
  38.         return this;    
  39.     }    
  40.     
  41.     //向量相加    
  42.     public MyPoint add(MyPoint p) {    
  43.         this.x += p.x;    
  44.         this.y += p.y;    
  45.         return this;    
  46.     }    
  47.     
  48.     public MyPoint set(int x, int y) {    
  49.         this.x = x;    
  50.         this.y = y;    
  51.         return this;    
  52.     }    
  53.     
  54.     @Override    
  55.     public String toString() {    
  56.         return "MyPoint{" +    
  57.                 "x=" + x +    
  58.                 ", y=" + y +    
  59.                 '}';    
  60.     }    
  61. }    

github地址
參考文章:http://www./demo/jiaoben1892/index.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多