本文主要内容为贝塞尔曲线原理解析并用 SurfaceView 实现其展示动画

关于SurfaceView 的使用,大家可以看我的上一篇文章 Android:SurfaceView 的使用(附代码模板)

概述

贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔曲线工具,如PhotoShop等。在Flash4中还没有完整的曲线工具,而在Flash5里面已经提供出贝塞尔曲线工具。

曲线作用

由于用计算机画图大部分时间是操作鼠标来掌握线条的路径,与手绘的感觉和效果有很大的差别。即使是一位精明的画师能轻松绘出各种图形,拿到鼠标想随心所欲的画图也不是一件容易的事。这一点是计算机万万不能代替手工的工作,所以到目前为止人们只能颇感无奈。使用贝塞尔工具画图很大程度上弥补了这一缺憾。贝塞尔曲线是计算机图形图像造型的基本工具,是图形造型运用得最多的基本线条之一。

贝塞尔曲线

——来自百度百科

如果大家用过 XMind 软件或者是 WPS 软件来绘制思维导图的话,那么对下面的连线一定不会陌生。下图中如果我们要连接两个分支主题,就会用到基于三阶贝塞尔曲线的连线功能,如下所示。我们先确定需要被连接起来的起始点和终点,然后拖动两个控制点就可以任意地绘制一条连接曲线。通过这篇文章,我为大家讲解一下贝塞尔曲线的实现原理,看完本文,你也可以轻轻松松实现这个炫酷的贝塞尔曲线。

XMind 示例

贝塞尔曲线公式

以下公式中:B(t)为t时间下 点的坐标;P0为起点,Pn为终点,Pi为控制点

一阶贝塞尔曲线公式(线性公式)

给定点P0、P1,线性贝兹曲线只是一条两点之间的直线。且其等同于线性插值。

一阶贝塞尔曲线

二阶贝塞尔曲线公式

设P0、P02、P2是一条曲线上顺序三个不同的点。过P0和P2点的两切线交于P1点,在P02点的切线交P0P1和P2P1于P01和P11,则如下比例成立:

当P0,P2固定,引入参数 t,令上述比值为 t:(1-t),即有:

将一式二式代入三式可得:

二阶贝塞尔曲线P02可以定义为分别由前两个顶点(P0,P1)和后两个顶点(P1,P2)决定的一阶贝塞尔曲线的线性组合。

可得出二阶贝塞尔曲线的公式:

三阶贝塞尔曲线公式

按照二阶的推导原理,以此类推,由四个控制点定义的三阶贝塞尔曲线P03可被定义为分别由(P0,P1,P2)和(P1,P2,P3)确定的两条二阶贝塞尔曲线的线性组合:P03 = (1-t)P02 + tP12

可递归代入得出三阶贝塞尔曲线公式:

现代的成象系统,如PostScript、Asymptote和Metafont,运用了以贝塞尔样条组成的三阶贝塞尔曲线,用来描绘曲线轮廓。

四阶及以上的贝塞尔曲线公式

由(n+1)个控制点 Pi(i=0,1,...,n) 定义的n阶贝塞尔曲线 P0n 可被定义为分别由前、后 n 个控制点定义的两条 (n-1) 阶贝塞尔曲线 P0n-1 与 P1n-1 的线性组合:

由此得到贝塞尔曲线的递推计算公式(通用公式):

其一般参数公式为:

n 阶贝塞尔曲线可如下推断。给定点P0、P1、…、Pn,其贝塞尔曲线即:

四阶贝塞尔曲线:

四阶贝塞尔曲线

五阶贝塞尔曲线:

五阶贝塞尔曲线

公式说明

开始于P0并结束于Pn的曲线,即所谓的端点插值法属性。

曲线是直线的充分必要条件是所有的控制点都位在曲线上。同样的,贝塞尔曲线是直线的充分必要条件是控制点共线。

曲线的起始点(结束点)相切于贝塞尔多边形的第一节(最后一节)。

一条曲线可在任意点切割成两条或任意多条子曲线,每一条子曲线仍是贝塞尔曲线。

一些看似简单的曲线(如圆)无法以贝塞尔曲线精确的描述,或分段成贝塞尔曲线(虽然当每个内部控制点对单位圆上的外部控制点水平或垂直的的距离为时,分成四段的贝塞尔曲线,可以小于千分之一的最大半径误差近似于圆)。

位于固定偏移量的曲线(来自给定的贝塞尔曲线),又称作偏移曲线(假平行于原来的曲线,如两条铁轨之间的偏移)无法以贝塞尔曲线精确的形成(某些琐屑实例除外)。无论如何,现存的启发法通常可为实际用途中给出近似值。

Android上实现贝赛尔曲线

在Android实现贝赛尔曲线,要借助android.graphics.Path,其中绘制贝赛尔曲线的方法在Api v1就已经提供了:

Path.moveTo(float x, float y) // Path的初始点

Path.lineTo(float x, float y) // 线性公式的贝赛尔曲线, 其实就是直线

Path.quadTo(float x1, float y1, float x2, float y2) // 二阶贝赛尔曲线

Path.cubicTo(float x1, float y1, float x2, float y2, float x3, float y3) // 三阶贝赛尔曲线

...

这上面是Java层调用的代码,最终调用的是Skia库的一系列方法,Skia是一个C++2D向量图形处理函数库,感兴趣的可以继续深入研究研究。

实现二阶贝塞尔曲线

一、首先来看一下可操作的二阶贝塞尔曲线动态图:

二阶贝塞尔曲线

自定义 MyBezierCurveQuadratic 类代码如下,很简单:

package com.example.pc.mybeziercurveview.view;

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;

/**

* 二阶

* Created by Deeson on 2017/5/24.

*/

public class MyBezierCurveQuadratic extends View{

private Paint mPaint;

private Path mPath;

private int centerX,centerY;

private PointF start,end,control;

public MyBezierCurveQuadratic(Context context) {

super(context);

init();

}

public MyBezierCurveQuadratic(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

public MyBezierCurveQuadratic(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private void init() {

mPaint = new Paint();

mPath = new Path();

mPaint.setColor(Color.BLACK);

mPaint.setStrokeWidth(8);

mPaint.setStyle(Paint.Style.STROKE);

mPaint.setTextSize(60);

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

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

//绘制数据点和控制点

mPaint.setColor(Color.GRAY);

mPaint.setStrokeWidth(20);

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

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

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

//绘制辅助线

mPaint.setStrokeWidth(4);

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

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

//绘制二阶贝塞尔曲线

mPaint.setColor(Color.RED);

mPaint.setStrokeWidth(8);

mPath.reset();

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

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

canvas.drawPath(mPath,mPaint);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction()){

case MotionEvent.ACTION_DOWN:

case MotionEvent.ACTION_MOVE:

control.x = event.getX();

control.y = event.getY();

invalidate();

break;

}

return true;

}

}

二、接着来看,如何用 SurfaceView 实现如下曲线动画效果:

关于SurfaceView 的使用,大家可以看我的上一篇文章 Android:SurfaceView 的使用(附代码模板)

二阶贝塞尔曲线show

这里,最关键的代码是开启子线程绘制二阶贝塞尔曲线,如下:

//辅助线坐标点

process1.x = (1 - t) * start.x + t * control.x;

process1.y = (1 - t) * start.y + t * control.y;

process2.x = (1 - t) * control.x + t * end.x;

process2.y = (1 - t) * control.y + t * end.y;

//贝塞尔曲线通用函数

x = (1 - t) * process1.x + t * process2.x;

y = (1 - t) * process1.y + t * process2.y;

mPath.lineTo(x, y);

//绘制数据点和控制点

mCanvas.drawPoint(start.x, start.y, mPointPaint);

mCanvas.drawPoint(control.x, control.y, mPointPaint);

mCanvas.drawPoint(end.x, end.y, mPointPaint);

//绘制数据点和控制点的连线

mCanvas.drawLine(start.x, start.y, control.x, control.y, mLinePaint);

mCanvas.drawLine(control.x, control.y, end.x, end.y, mLinePaint);

//绘制辅助线和辅助点

mCanvas.drawLine(process1.x, process1.y, process2.x, process2.y, mAssistLinePaint);

mCanvas.drawPoint(process1.x,process1.y,mAssistPointPaint);

mCanvas.drawPoint(process2.x,process2.y,mAssistPointPaint);

//绘制二阶贝塞尔曲线的当前点

mCanvas.drawPoint(x, y, mPointPaint);

//绘制二阶贝塞尔曲线

mCanvas.drawPath(mPath, mPaint);

自定义 QuadraticBezierShowView 类的完整代码如下:

package com.example.pc.mybeziercurveview.view;

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.SurfaceHolder;

import android.view.SurfaceView;

/**

* 二阶

* Created by Deeson on 2017/5/24.

*/

public class QuadraticBezierShowView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

//分别对应贝塞尔曲线、点、数据点和控制点之间的线、辅助线、辅助点

private Paint mPaint, mPointPaint, mLinePaint, mAssistLinePaint,mAssistPointPaint;

//绘制贝塞尔曲线的path

private Path mPath;

//布局的中心点

private int centerX, centerY;

//分别对应贝塞尔曲线的起点、终点、控制点、辅助线的起点、终点

private PointF start, end, control, process1, process2;

private SurfaceHolder mHolder;

//用于绘图的canvas

private Canvas mCanvas;

//子线程标志位

private boolean mIsDrawing;

float x = 0;//贝塞尔曲线的实时点x坐标

float y = 0;//贝塞尔曲线的实时点y坐标

float t = 0;//实施进度,0<=t<=1

public QuadraticBezierShowView(Context context) {

super(context);

init();

}

public QuadraticBezierShowView(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

public QuadraticBezierShowView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private void init() {

mPaint = new Paint();

mPath = new Path();

mPaint.setColor(Color.RED);

mPaint.setStrokeWidth(5);

mPaint.setStyle(Paint.Style.STROKE);

mPaint.setTextSize(60);

mPointPaint = new Paint();

mPointPaint.setColor(Color.BLACK);

mPointPaint.setStrokeWidth(10);

mPointPaint.setStyle(Paint.Style.STROKE);

mLinePaint = new Paint();

mLinePaint.setColor(Color.GRAY);

mLinePaint.setStrokeWidth(4);

mLinePaint.setStyle(Paint.Style.STROKE);

mAssistLinePaint = new Paint();

mAssistLinePaint.setColor(Color.GREEN);

mAssistLinePaint.setStrokeWidth(4);

mAssistLinePaint.setStyle(Paint.Style.STROKE);

mAssistPointPaint = new Paint();

mAssistPointPaint.setColor(Color.GREEN);

mAssistPointPaint.setStrokeWidth(10);

mAssistPointPaint.setStyle(Paint.Style.FILL);

start = new PointF(0, 0);

end = new PointF(0, 0);

control = new PointF(0, 0);

process1 = new PointF(0, 0);

process2 = new PointF(0, 0);

mHolder = getHolder();

mHolder.addCallback(this);

setFocusable(true);

setFocusableInTouchMode(true);

this.setKeepScreenOn(true);

}

@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 - 50;

control.y = centerY - 300;

x = start.x;

y = start.y;

mPath.moveTo(x, y);

}

@Override

public void surfaceCreated(SurfaceHolder holder) {

mIsDrawing = true;

new Thread(this).start();

}

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override

public void surfaceDestroyed(SurfaceHolder holder) {

mIsDrawing = false;

}

@Override

public void run() {

while (mIsDrawing) {

draw();

if (t <= 1) {

t += 0.003;

//辅助线坐标点

process1.x = (1 - t) * start.x + t * control.x;

process1.y = (1 - t) * start.y + t * control.y;

process2.x = (1 - t) * control.x + t * end.x;

process2.y = (1 - t) * control.y + t * end.y;

//贝塞尔曲线通用函数

x = (1 - t) * process1.x + t * process2.x;

y = (1 - t) * process1.y + t * process2.y;

//二阶贝塞尔曲线函数

// x = (float) (Math.pow((1 - t), 2) * start.x + 2 * t * (1 - t) * control.x + Math.pow(t, 2) * end.x);

// y = (float) (Math.pow((1 - t), 2) * start.y + 2 * t * (1 - t) * control.y + Math.pow(t, 2) * end.y);

mPath.lineTo(x, y);

} else {

mIsDrawing = false;

}

}

}

private void draw() {

try {

mCanvas = mHolder.lockCanvas();

mCanvas.drawColor(Color.WHITE);

//绘制数据点和控制点

mCanvas.drawPoint(start.x, start.y, mPointPaint);

mCanvas.drawPoint(control.x, control.y, mPointPaint);

mCanvas.drawPoint(end.x, end.y, mPointPaint);

//绘制数据点和控制点的连线

mCanvas.drawLine(start.x, start.y, control.x, control.y, mLinePaint);

mCanvas.drawLine(control.x, control.y, end.x, end.y, mLinePaint);

//绘制辅助线和辅助点

mCanvas.drawLine(process1.x, process1.y, process2.x, process2.y, mAssistLinePaint);

mCanvas.drawPoint(process1.x,process1.y,mAssistPointPaint);

mCanvas.drawPoint(process2.x,process2.y,mAssistPointPaint);

//绘制二阶贝塞尔曲线的当前点

mCanvas.drawPoint(x, y, mPointPaint);

//绘制二阶贝塞尔曲线

mCanvas.drawPath(mPath, mPaint);

} catch (Exception e) {

e.printStackTrace();

} finally {

if (null != mCanvas) {

mHolder.unlockCanvasAndPost(mCanvas);

}

}

}

}

实现三阶贝塞尔曲线

一、同样的,先看看可操作的三阶贝塞尔曲线:

三阶贝塞尔曲线

自定义 MyBezierCurveCubic 类的完整代码如下:

package com.example.pc.mybeziercurveview.view;

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;

/**

* 三阶

* Created by Deeson on 2017/5/24.

*/

public class MyBezierCurveCubic extends View{

private Paint mPaint;

private Path mPath;

private int centerX,centerY;

private PointF start,end,control1,control2;

public static final int CONTROL_ONE = 0;

public static final int CONTROL_TWO = 1;

private int control = CONTROL_ONE;

public MyBezierCurveCubic(Context context) {

super(context);

init();

}

public MyBezierCurveCubic(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

public MyBezierCurveCubic(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private void init() {

mPaint = new Paint();

mPath = new Path();

mPaint.setColor(Color.BLACK);

mPaint.setStrokeWidth(8);

mPaint.setStyle(Paint.Style.STROKE);

start = new PointF(0,0);

end = new PointF(0,0);

control1 = new PointF(0,0);

control2 = 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;

control1.x = centerX - 200;

control1.y = centerY - 200;

control2.x = centerX + 200;

control2.y = centerY + 200;

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

//绘制数据点和控制点

mPaint.setColor(Color.GRAY);

mPaint.setStrokeWidth(20);

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

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

canvas.drawPoint(control1.x,control1.y,mPaint);

canvas.drawPoint(control2.x, control2.y, mPaint);

//绘制辅助线

mPaint.setStrokeWidth(4);

canvas.drawLine(start.x, start.y, control1.x, control1.y, mPaint);

canvas.drawLine(control1.x, control1.y, control2.x, control2.y, mPaint);

canvas.drawLine(control2.x, control2.y, end.x, end.y, mPaint);

//绘制三阶贝塞尔曲线

mPaint.setColor(Color.RED);

mPaint.setStrokeWidth(8);

mPath.reset();

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

mPath.cubicTo(control1.x,control1.y,control2.x,control2.y,end.x,end.y);

canvas.drawPath(mPath,mPaint);

}

public void setControl(int control){

this.control = control;

}

@Override

public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction()){

case MotionEvent.ACTION_DOWN:

case MotionEvent.ACTION_MOVE:

if(control == CONTROL_ONE){

control1.x = event.getX();

control1.y = event.getY();

}else{

control2.x = event.getX();

control2.y = event.getY();

}

invalidate();

break;

}

return true;

}

}

二、接着来看,如何用 SurfaceView 实现如下三阶贝塞尔曲线动画效果:

关于SurfaceView 的使用,大家可以看我的上一篇文章 Android:SurfaceView 的使用(附代码模板)

三阶贝塞尔曲线show

自定义 CubicBezierShowView 类的完整代码如下:

package com.example.pc.mybeziercurveview.view;

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.SurfaceHolder;

import android.view.SurfaceView;

/**

* 三阶

* Created by Deeson on 2016/7/12.

*/

public class CubicBezierShowView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

//分别对应贝塞尔曲线、点、数据点和控制点之间的线、第一层辅助线、第一层辅助点、第二层辅助线、第二层辅助点

private Paint mPaint, mPointPaint, mLinePaint, mAssistLine1Paint, mAssistPoint1Paint, mAssistLine2Paint, mAssistPoint2Paint;

//绘制贝塞尔曲线的path

private Path mPath;

//布局的中心点

private int centerX, centerY;

//分别对应三阶贝塞尔曲线的起点、终点、控制点

private PointF start, end, control1, control2;

//第一层辅助线的3个端点(相当于动态的二阶贝塞尔曲线的起点,控制点,终点)

private PointF process1, process2, process3;

//第二层辅助线的起点和终点

private PointF secondProcess1, secondProcess2;

private SurfaceHolder mHolder;

//用于绘图的canvas

private Canvas mCanvas;

//子线程标志位

private boolean mIsDrawing;

float x = 0;//贝塞尔曲线的实时点x坐标

float y = 0;//贝塞尔曲线的实时点y坐标

float t = 0;//实施进度,0<=t<=1

public CubicBezierShowView(Context context) {

super(context);

init();

}

public CubicBezierShowView(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

public CubicBezierShowView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private void init() {

//贝塞尔曲线

mPaint = new Paint();

mPath = new Path();

mPaint.setColor(Color.RED);

mPaint.setStrokeWidth(5);

mPaint.setStyle(Paint.Style.STROKE);

mPaint.setTextSize(60);

//点

mPointPaint = new Paint();

mPointPaint.setColor(Color.BLACK);

mPointPaint.setStrokeWidth(10);

mPointPaint.setStyle(Paint.Style.STROKE);

//数据点和控制点的连线

mLinePaint = new Paint();

mLinePaint.setColor(Color.GRAY);

mLinePaint.setStrokeWidth(4);

mLinePaint.setStyle(Paint.Style.STROKE);

//第一层辅助线

mAssistLine1Paint = new Paint();

mAssistLine1Paint.setColor(Color.GREEN);

mAssistLine1Paint.setStrokeWidth(4);

mAssistLine1Paint.setStyle(Paint.Style.STROKE);

//第一层辅助点

mAssistPoint1Paint = new Paint();

mAssistPoint1Paint.setColor(Color.GREEN);

mAssistPoint1Paint.setStrokeWidth(10);

mAssistPoint1Paint.setStyle(Paint.Style.FILL);

//第二层辅助线

mAssistLine2Paint = new Paint();

mAssistLine2Paint.setColor(Color.BLUE);

mAssistLine2Paint.setStrokeWidth(4);

mAssistLine2Paint.setStyle(Paint.Style.STROKE);

//第二层辅助线

mAssistPoint2Paint = new Paint();

mAssistPoint2Paint.setColor(Color.BLUE);

mAssistPoint2Paint.setStrokeWidth(10);

mAssistPoint2Paint.setStyle(Paint.Style.FILL);

//三阶贝塞尔曲线的起点终点

start = new PointF(0, 0);

end = new PointF(0, 0);

//三阶贝塞尔曲线的两个控制点

control1 = new PointF(0, 0);

control2 = new PointF(0, 0);

//第一层辅助线的三个端点

process1 = new PointF(0, 0);

process2 = new PointF(0, 0);

process3 = new PointF(0, 0);

//第二层辅助线的两个端点

secondProcess1 = new PointF(0, 0);

secondProcess2 = new PointF(0, 0);

mHolder = getHolder();

mHolder.addCallback(this);

setFocusable(true);

setFocusableInTouchMode(true);

this.setKeepScreenOn(true);

}

@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;

control1.x = centerX - 150;

control1.y = centerY - 300;

control2.x = centerX + 170;

control2.y = centerY - 340;

x = start.x;

y = start.y;

mPath.moveTo(x, y);

}

@Override

public void surfaceCreated(SurfaceHolder holder) {

mIsDrawing = true;

new Thread(this).start();

}

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override

public void surfaceDestroyed(SurfaceHolder holder) {

mIsDrawing = false;

}

@Override

public void run() {

while (mIsDrawing) {

draw();

if (t <= 1) {

t += 0.003;

//重点在这里

bezierDraw();

mPath.lineTo(x, y);

} else {

mIsDrawing = false;

}

}

}

private void draw() {

try {

mCanvas = mHolder.lockCanvas();

mCanvas.drawColor(Color.WHITE);

//绘制数据点和控制点

mCanvas.drawPoint(start.x, start.y, mPointPaint);

mCanvas.drawPoint(control1.x, control1.y, mPointPaint);

mCanvas.drawPoint(control2.x, control2.y, mPointPaint);

mCanvas.drawPoint(end.x, end.y, mPointPaint);

//绘制数据点和控制点的连线

mCanvas.drawLine(start.x, start.y, control1.x, control1.y, mLinePaint);

mCanvas.drawLine(control1.x, control1.y, control2.x, control2.y, mLinePaint);

mCanvas.drawLine(control2.x, control2.y, end.x, end.y, mLinePaint);

//绘制第一层辅助线和辅助点

mCanvas.drawLine(process1.x, process1.y, process2.x, process2.y, mAssistLine1Paint);

mCanvas.drawLine(process2.x, process2.y, process3.x, process3.y, mAssistLine1Paint);

mCanvas.drawPoint(process1.x, process1.y, mAssistPoint1Paint);

mCanvas.drawPoint(process2.x, process2.y, mAssistPoint1Paint);

mCanvas.drawPoint(process3.x, process3.y, mAssistPoint1Paint);

//绘制第二层辅助线和辅助点

mCanvas.drawLine(secondProcess1.x, secondProcess1.y, secondProcess2.x, secondProcess2.y, mAssistLine2Paint);

mCanvas.drawPoint(secondProcess1.x, secondProcess1.y, mAssistPoint2Paint);

mCanvas.drawPoint(secondProcess2.x, secondProcess2.y, mAssistPoint2Paint);

//绘制三阶贝塞尔曲线的当前点

mCanvas.drawPoint(x, y, mPointPaint);

//绘制三阶贝塞尔曲线

mCanvas.drawPath(mPath, mPaint);

} catch (Exception e) {

e.printStackTrace();

} finally {

if (null != mCanvas) {

mHolder.unlockCanvasAndPost(mCanvas);

}

}

}

private void bezierDraw() {

//第一层辅助线坐标点

process1.x = (1 - t) * start.x + t * control1.x;

process1.y = (1 - t) * start.y + t * control1.y;

process2.x = (1 - t) * control1.x + t * control2.x;

process2.y = (1 - t) * control1.y + t * control2.y;

process3.x = (1 - t) * control2.x + t * end.x;

process3.y = (1 - t) * control2.y + t * end.y;

//第二层辅助线坐标点

secondProcess1.x = (1 - t) * process1.x + t * process2.x;

secondProcess1.y = (1 - t) * process1.y + t * process2.y;

secondProcess2.x = (1 - t) * process2.x + t * process3.x;

secondProcess2.y = (1 - t) * process2.y + t * process3.y;

//贝塞尔曲线通用公式

x = (1 - t) * secondProcess1.x + t * secondProcess2.x;

y = (1 - t) * secondProcess1.y + t * secondProcess2.y;

//三阶贝塞尔曲线函数

// x = (float) (Math.pow((1 - t), 3) * start.x + 3 * t * Math.pow((1 - t), 2) * control1.x + 3 * Math.pow(t, 2) * (1 - t) * control2.x + Math.pow(t, 3) * end.x);

// y = (float) (Math.pow((1 - t), 3) * start.y + 3 * t * Math.pow((1 - t), 2) * control1.y + 3 * Math.pow(t, 2) * (1 - t) * control2.y + Math.pow(t, 3) * end.y);

}

}

最后

Demo下载地址 点这里,Demo里还有四阶曲线的展示,可以看看,原理与二阶三阶雷同,就不贴代码了。

python 贝塞尔曲线,贝塞尔曲线原理分析及其Android的实现相关推荐

  1. Android深色模式适配原理分析,android应用开发

    return when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) { Configuration.UI ...

  2. xposed hook java_[原创]Android Hook 系列教程(一) Xposed Hook 原理分析

    章节内容 一. Android Hook 系列教程(一) Xposed Hook 原理分析 二. Android Hook 系列教程(二) 自己写APK实现Hook Java层函数 三. Androi ...

  3. 贝塞尔曲线的数学原理

    Bézier curve(贝塞尔曲线)是应用于二维图形应用程序的数学曲线. 曲线定义:起始点.终止点(也称锚点).控制点.通过调整控制点,贝塞尔曲线的形状会发生变化. 1962年,法国数学家Pierr ...

  4. 贝塞尔曲线轨迹运动原理与实战

    大厂技术  坚持周更  精选好文 本次分享大概分为下面几个方面 背景 贝塞尔曲线讲解 实现和探索过程 背景 近期在 X 业务测评报告页有一个需求,用户可以左右拖动滑块来查看各个等级的信息. 在之前的野 ...

  5. python如何画贝塞尔曲线_初识贝塞尔曲线

    贝塞尔曲线在CSS动画中和canvas.svg绘图中都是比较重要的一个东西!所以我来好好的小结一下关于它的一些东西. 什么是贝塞尔曲线 贝塞尔曲线于1962,由法国工程师皮埃尔·贝塞尔(Pierre ...

  6. php 贝瑟尔曲线,贝塞尔曲线的应用详解

    简介 贝塞尔曲线是可以做出很多复杂的效果来的,比如弹跳球的复杂动画效果,首先加速下降,停止,然后弹起时逐渐减速的效果. 使用贝塞尔曲线常用的两个网址如下: 缓动函数: cubic-bezier: 如何 ...

  7. WPF将点列连接成光滑曲线——贝塞尔曲线

    背景 最近在写一个游戏场景编辑器,虽然很水,但是还是遇到了不少问题.连接离散个点列成为光滑曲线就是一个问题.主要是为了通过关键点产生2D的赛道场景.总之马路不可能是直线相连的,当然需要曲线光滑相连.现 ...

  8. python解析can报文,Python实现Can接收发送 DBC分析报文 周立功ZLG 绘制曲线 支持离线回放.rar...

    [实例简介] Python实现Can接收发送 DBC分析报文 绘制曲线 支持离线回放 CAN分析工具 环境:windows & python3 设备:周立功USBCAN-I(可在源码中修改支持 ...

  9. indesign如何画弧线_使用CorelDRAW贝塞尔工具绘制曲线

    原标题:使用CorelDRAW贝塞尔工具绘制曲线 说到Photoshop.Fireworks.这些设计软件里的"贝赛尔"工具,大家不一定很熟悉,也不一定了解它的重要性.所以很多朋友 ...

最新文章

  1. pandas高级处理-分组与聚合
  2. Potala(3)——Transaction
  3. 用python写数字_用python 写游戏之数字华容道
  4. 基于帝国cms 7.5带支付个人也可以使用的h5微信商城
  5. 你对Java网络编程了解的如何?Java NIO 网络编程 | Netty前期知识(二)
  6. php+mysql+html 之页面输入、输出
  7. Linux学习资料-万用字符与特殊符号
  8. CMD下查询Mysql中文乱码的解决方法
  9. 二叉树的锯齿形层次遍历
  10. Android的Fragment介绍
  11. 在计算机中dos代表什么意思,Boot是什么意思
  12. vscode 连接docker_在VS Code中使用带Docker容器的Java开发环境 – Bruno Borge
  13. poj2991(Crane)线段树+计算几何
  14. eclipse-Tomcat运行项目笔记
  15. centos journalctl日志查看
  16. php微信昵称保存,附件十四 存储微信昵称的处理方法
  17. #Geek Point# 八年了,消费级智能眼镜到底该怎么做?
  18. 《Learning Scheduling Algorithms for Data Processing Clusters》
  19. 搬运+机翻 Unity插件 OBICloth插件官方CharDemo分析
  20. python seaborn学习笔记

热门文章

  1. 做外贸SOHO如何收汇
  2. JavaScript (一)
  3. CodeForces 630K Indivisibility (容斥)
  4. 为什么有人说 Python 多线程是鸡肋
  5. 阿里云服务器CUP爆满被用来当挖矿机(要疯!!!!)
  6. 雅虎欧洲推Yahoo! Go 3.0程序和移动器件
  7. 工业设计师不可不知的网站
  8. AO3401-ASEMI低功耗mos管
  9. Reabble.com - Kindle RSS新闻杂志订阅
  10. 九校联考-长沙市一中NOIP模拟Day2T3 柱状图(column)