Android -- 贝塞尔曲线公式的推导
1,最近看了几个不错的自定义view,发现里面都会涉及到贝塞尔曲线知识,深刻的了解到贝塞尔曲线是进阶自定义view的一座大山,so,今天先和大家来了解了解。
2,贝塞尔曲线作用十分广泛,简单举几个的栗子:
QQ小红点拖拽效果
360火箭发射
加入购物车动画
一些炫酷的下拉刷新控件
阅读软件的翻书效果
一些平滑的折线图的制作
很多炫酷的动画效果
这么多好看的效果,难道不想自己也写一个吗。。。。
- 理解贝塞尔曲线的原理
贝塞尔曲线是用一系列点来控制曲线状态的,我将这些点简单分为两类:数据点、控制点。通过调整控制点,贝塞尔曲线形状会发生变化。
数据点:确定曲线的起始和结束位置
控制点:确定曲线的弯曲程度
- 一阶曲线原理
一阶曲线是没有控制点的,仅有两个数据点(A 和 B),最终效果一个线段。
一阶公式如下:
- 二阶曲线原理
二阶曲线由两个数据点(A 和 C),一个控制点(B)来描述曲线状态,大致如下:
那么ac之间的红线是怎么生成的呢,让我们了解一下
在AB线段和BC线段分别去D、E两点,且满足条件
连接DE,取点F,使得: ,这样获取到的点F就是贝塞尔曲线上的一个点,动态图如下:
二阶公式如下:
三阶曲线原理
三阶曲线由两个数据点(A 和 D),两个控制点(B 和 C)来描述曲线状态
动态图如下:
三阶公式如下:
- 四阶曲线
- 五阶曲线
通用公式:
3,公式推导
由于博客园的编辑器无法编写高数公式,所以我这里就在纸上写了,如果有点看不到的话可以把图片下下来再放大看看(见谅)
4,实现简单的小例子
在我们Android中Path类中其实是有已经封装好了关于贝塞尔曲线的函数的
//二阶贝赛尔
public void quadTo(float x1, float y1, float x2, float y2)
public void rQuadTo(float dx1, float dy1, float dx2, float dy2)
//三阶贝赛尔
public void cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)
public void rCubicTo(float x1, float y1, float x2, float y2,float x3, float y3)
- quadTo()方法
让我们先来看一下源码
/**
* Add a quadratic bezier from the last point, approaching control point
* (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
* this contour, the first point is automatically set to (0,0).
*
* @param x1 The x-coordinate of the control point on a quadratic curve
* @param y1 The y-coordinate of the control point on a quadratic curve
* @param x2 The x-coordinate of the end point on a quadratic curve
* @param y2 The y-coordinate of the end point on a quadratic curve
*/
public void quadTo(float x1, float y1, float x2, float y2) {
isSimplePath = false;
native_quadTo(mNativePath, x1, y1, x2, y2);
}
从源码的注释上我们可以得到的信息如下:参数中(x1,y1)是控制点坐标,(x2,y2)是终点坐标 。
大家可能会有一个疑问:有控制点和终点坐标,那起始点是多少呢? 整条线的起始点是通过Path.moveTo(x,y)来指定的,而如果我们连续调用quadTo(),前一个quadTo()的终点,就是下一个quadTo()函数的起点;如果初始没有调用Path.moveTo(x,y)来指定起始点,则默认以控件左上角(0,0)为起始点;
我们简单的写一下demo,通过我们点击屏幕来动态的获取点击屏幕的坐标,然后将其设置成贝二阶塞尔曲线的控制点,代码很简单
package com.qianmo.beziertest.view; import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View; import com.qianmo.beziertest.R; /**
* Created by Administrator on 2017/3/30 0030.
* E-Mail:543441727@qq.com
*/ public class MyView extends View { private Point controlPoint = new Point(200, 200); public MyView(Context context) {
super(context);
} public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
} public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.BLACK);
paint.setStrokeWidth(10); Path path = new Path();
path.moveTo(100, 500);
path.quadTo(controlPoint.x, controlPoint.y, 700, 500);
//绘制路径
canvas.drawPath(path, paint);
//绘制辅助点
canvas.drawPoint(controlPoint.x,controlPoint.y,paint); } @Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
controlPoint.x = (int) event.getX();
controlPoint.y = (int) event.getY();
invalidate();
break;
}
return true;
}
}
效果图如下:
- rQuadTo()
先来看一下它的源码,代码如下:
/**
* Same as quadTo, but the coordinates are considered relative to the last
* point on this contour. If there is no previous point, then a moveTo(0,0)
* is inserted automatically.
*
* @param dx1 The amount to add to the x-coordinate of the last point on
* this contour, for the control point of a quadratic curve
* @param dy1 The amount to add to the y-coordinate of the last point on
* this contour, for the control point of a quadratic curve
* @param dx2 The amount to add to the x-coordinate of the last point on
* this contour, for the end point of a quadratic curve
* @param dy2 The amount to add to the y-coordinate of the last point on
* this contour, for the end point of a quadratic curve
*/
public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
isSimplePath = false;
native_rQuadTo(mNativePath, dx1, dy1, dx2, dy2);
}
从上面的方法注释我们可以看到,这是一个相对坐标,具体参数意思如下:
dx1:控制点X坐标,表示相对上一个终点X坐标的位移坐标,可为负值,正值表示相加,负值表示相减;
dy1:控制点Y坐标,相对上一个终点Y坐标的位移坐标。同样可为负值,正值表示相加,负值表示相减;
dx2:终点X坐标,同样是一个相对坐标,相对上一个终点X坐标的位移值,可为负值,正值表示相加,负值表示相减;
dy2:终点Y坐标,同样是一个相对,相对上一个终点Y坐标的位移值。可为负值,正值表示相加,负值表示相减;
这里举个例子,假如我们上一个终点坐标是(300,400)那么利用rQuadTo(100,-100,200,100); 得到的控制点坐标是(300+100,400-100)即(500,300) 同样,得到的终点坐标是(300+200,400+100)即(500,500),这个方法和quadTo()方法没什么区别,所以就不写Demo写了
- cubicTo()
这是Android的三阶贝塞尔曲线方法,先来看一下每一参数的意义
/**
* Add a cubic bezier from the last point, approaching control points
* (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
* made for this contour, the first point is automatically set to (0,0).
*
* @param x1 The x-coordinate of the 1st control point on a cubic curve
* @param y1 The y-coordinate of the 1st control point on a cubic curve
* @param x2 The x-coordinate of the 2nd control point on a cubic curve
* @param y2 The y-coordinate of the 2nd control point on a cubic curve
* @param x3 The x-coordinate of the end point on a cubic curve
* @param y3 The y-coordinate of the end point on a cubic curve
*/
public void cubicTo(float x1, float y1, float x2, float y2,
float x3, float y3) {
isSimplePath = false;
native_cubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
}
从上面源码可以看到参数(x1,y1)是第一个控制点坐标,(x2,y2)是第二个控制点坐标,(x3,y3)是终点坐标。
整条线的起始点是通过Path.moveTo(x,y)来指定的,而如果我们连续调用cubicTo(),前一个cubicTo()的终点,就是下一个cubicTo()函数的起点;如果初始没有调用Path.moveTo(x,y)来指定起始点,则默认以控件左上角(0,0)为起始点;和我们的quadTo()方法一样。
下面也是通过一个小例子给大家看一下效果,和二阶贝塞尔曲线一样,就是多了一个控制点代码如下:
package com.qianmo.beziertest.view; import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View; /**
* Created by wangjitao on 2017/3/30 0030.
* E-Mail:543441727@qq.com
*/ public class MyView1 extends View { private Point controlPointOne = new Point(200, 200);
private Point controlPointTwo = new Point(500, 200); private boolean isControlPointTwo ; private Paint paintBezier;
private Paint paintLine; public MyView1(Context context) {
this(context, null);
} public MyView1(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
} public MyView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); paintBezier = new Paint();
paintBezier.setStyle(Paint.Style.STROKE);
paintBezier.setColor(Color.BLACK);
paintBezier.setStrokeWidth(10); paintLine = new Paint();
paintLine.setStyle(Paint.Style.STROKE);
paintLine.setColor(Color.RED);
paintLine.setStrokeWidth(3); } @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); Path path = new Path();
path.moveTo(100, 500);
path.cubicTo(controlPointOne.x, controlPointOne.y,controlPointTwo.x, controlPointTwo.y, 900, 500);
//绘制路径
canvas.drawPath(path, paintBezier);
//绘制辅助点
canvas.drawPoint(controlPointOne.x, controlPointOne.y, paintBezier);
canvas.drawPoint(controlPointTwo.x, controlPointTwo.y, paintBezier);
//绘制连线
// canvas.drawLine(100, 500, controlPointOne.x, controlPointOne.y, paintLine);
// canvas.drawLine(900, 500, controlPointOne.x, controlPointOne.y, paintLine);
} @Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
if (isControlPointTwo){
controlPointOne.x = (int) event.getX();
controlPointOne.y = (int) event.getY();
}else {
controlPointTwo.x = (int) event.getX();
controlPointTwo.y = (int) event.getY();
}
invalidate();
break;
}
return true;
} public boolean isControlPointTwo() {
return isControlPointTwo;
} public void setControlPointTwo(boolean controlPointTwo) {
isControlPointTwo = controlPointTwo;
}
}
效果如下:
同理rCubicTo,这里就不给大家解释了
ok,本篇基本上把贝塞尔的基础知识都了解完了,明天开始试着来撸撸轮子,感觉一大波好看的动画满天飞的控件在等着我们(邪恶脸)。See You Next Time。。。。
Android -- 贝塞尔曲线公式的推导的更多相关文章
- Android -- 贝塞尔曲线公式的推导和简单使用
1,最近看了几个不错的自定义view,发现里面都会涉及到贝塞尔曲线知识,深刻的了解到贝塞尔曲线是进阶自定义view的一座大山,so,今天先和大家来了解了解. 2,贝塞尔曲线作用十分广泛,简单举几个的栗 ...
- Android 贝塞尔曲线 折线图
1.贝塞尔曲线:http://baike.baidu.com/view/60154.htm,在这里理解什么是贝塞尔曲线 2.直接上图: 3.100多行代码就可以画出贝塞尔曲线,直接上代码 packag ...
- Android 贝塞尔曲线解析
相信很多同学都知道"贝塞尔曲线"这个词,我们在很多地方都能经常看到.利用"贝塞尔曲线"可以做出很多好看的UI效果,本篇博客就让我们一起学习"贝塞尔曲线 ...
- Android 贝塞尔曲线的浅析
博客也开了挺长时间了,一直都没有来写博客,主要原因是自己懒---此篇博客算是给2017年一个好的开始,同时也给2016年画上一个句点,不留遗憾. 那就让我们正式进入今天的主题:贝塞尔曲线. 首先,让我 ...
- Android 贝塞尔曲线库
最近做的一个小项目需要绘制一些折线图,AChartEngine其实里面包含很多图,虽然是开源的,但毕竟不是自己写的,而且项目稍有点庞大,有些东西修改起来还是得花点时间的,所以最后打算自己写一个,参考了 ...
- Android 贝塞尔曲线
博客图片备份位置:
- Android贝塞尔曲线应用-跳动的水滴
主要通过6个控制点实现. val startPoint = PointF() val endPoint = PointF() val control1 = PointF() val control2 ...
- Android 利用二次贝塞尔曲线模仿购物车加入物品抛物线动画
Android 利用二次贝塞尔曲线模仿购物车加入物品抛物线动画 0.首先.先给出一张效果gif图. 1.贝塞尔曲线原理及相关公式參考:http://www.jianshu.com/p/c0d7ad79 ...
- Android仿苹果版QQ下拉刷新实现(二) ——贝塞尔曲线开发"鼻涕"下拉粘连效果
前言 接着上一期Android仿苹果版QQ下拉刷新实现(一) ——打造简单平滑的通用下拉刷新控件 的博客开始,同样,在开始前我们先来看一下目标效果: 下面上一下本章需要实现的效果图: 大家看到这个效果 ...
随机推荐
- 告诉你 IOS9.0 之后的Bitcode到底是什么!!
用Xcode 7 beta 3在真机(iOS 8.3)上运行一下工程,结果发现工程编译不过.看了下问题,报的是以下错误: ld: ‘/Users/**/Framework/SDKs/PolymerPa ...
- Linux的CentOS7系统下配置LNMP
友情提示:在执行以下操作之前,请确保您已经安装了centos7,因为以下所有操作均是在centos7下操作完成的. 1.首先要停掉本机自带的防火墙,再配置iptables,开放21/22/80/808 ...
- Monit:开源服务器监控工具
Monit是一个跨平台的用来监控Unix/linux系统(比如Linux.BSD.OSX.Solaris)的工具.Monit特别易于安装,而且非常轻量级(只有500KB大小),并且不依赖任何第三方程序 ...
- 【原创】NuGet 出现“无法初始化 PowerShell 主机,如果将你的 PowerShell 执行策略设置设置为 AllSigned ,请先打开程序包管理控制台以初始化该主机” 错误的解决方法
现象: 网上的设置 AllSigned 等方法都无效..后来考虑可能跟命令行版本兼容性有关系,然后在注册表命令行配置里发现一 ForceV2 设置项,抱着试一试的心态改了下,果然解决了! 解决方法:修 ...
- Dynamics CRM 2015-Custom Workflow Activity
CRM的Workflow给我们的流程处理带来不少便利,但是这种自带的Workflow并不是万能的,中间某一step不能支持,往往会牵一发而动全身,可能造成整个Workflow Steps的重新设计.幸 ...
- C# 6 与 .NET Core 1.0 高级编程 - 40 ASP.NET Core(下)
译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 40 章 ASP.NET Core(下)),不对的地方欢迎指出与交流. 章节出自<Professiona ...
- UU农场平台开发 UU农场拆复利系统
UU农场平台开发 UU农场拆复利系统今年比较新的一款游戏,类似于QQ农场,但又加入了很多新型的互联网理财模式!UU农场平台开发 UU农场拆复利系统.UU农场开发.UU农场游戏平台开发.UU农场平台开发 ...
- 关于jquery中封装函数如何传递当前元素的问题
需要对页面上一组元素进行ajax操作 <div id="aid"></div> <div id="aid"></div ...
- python爬虫利器Selenium使用详解
简介: 用pyhon爬取动态页面时普通的urllib2无法实现,例如下面的京东首页,随着滚动条的下拉会加载新的内容,而urllib2就无法抓取这些内容,此时就需要今天的主角selenium. Sele ...
- Java虚拟机学习 - 体系结构 内存模型(1)
一:Java技术体系模块图 二:JVM内存区域模型 1.方法区 也称"永久代" ."非堆", 它用于存储虚拟机加载的类信息.常量.静态变量.是各个线程共享的内 ...