标签:
贝塞尔曲线在android中运用广泛,可以用来绘制各类复杂曲线,因为贝塞尔曲线只需要指定控制点,就能绘制出特定的曲线。其次是做点和点的平滑过渡。为什么可以做到如上两点,看下面的讲解:
首先来说,贝塞尔曲线有阶的概念,这个阶可以理解为控制点,一阶的控制点只有两个。如上是一阶的方程,其中t取值为0到1,可以理解为时间,从开始到结束。动图如下:
图中可以看到,点随着t的变化从p0到p1运动,一阶的贝塞尔其实就是一条直线。
那么二阶又是如何呢:
方程如上,可以通过一阶方程推导出来,这里不做演算,看看动图:
动图中可以看到,有3个控制点。在控制点p0到p1之间有一个点随着t变化而运动,在p1到p2之间也有点随着变动,他们两个点遵循一阶方程,而两个点的连线上又有一个点随着t运动,这个点也遵循一阶方程,所以可以推导出上诉方程。
再来看看三阶方程和动图:
!
接下来是四阶和五阶的贝塞尔曲线动图:
从上面的图中可以看出:
1. 贝塞尔曲线,可以由控制点来控制曲线的走势。
1. 拐点处,曲线可以平滑过渡
由以上两点结论,可以看出,贝塞尔曲线可以用来方便简单的绘制各类曲线,同时,可以用于平滑处理拐点。后面将讲解示例。
//二阶
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)
在Path类中有如上四个方法是有关于贝塞尔曲线的,其中前面两个是二阶,后面两个是三阶。
这里quadTo以及cubicTo方法都是直接接收控制点的坐标,而rQuadTo以及rCubicTo接收的是相对坐标,即相对上一个控制点的相对坐标
例如:
path.moveTo(100,300);
path.rQuadTo(100,-100,200,0);
path.rQuadTo(100,100,200,0);
等价于
path.moveTo(100,300);
path.quadTo(200,200,300,300);
path.quadTo(400,400,500,300);
假设我们有四个个数据点,需要绘制出他们组成的连线,数据点数据为{200, 500},{400, 700}{600, 300}{800, 1000}。那么绘制出来的结果如下:
这就是四个点依次连接所组成的连线,看起来是没有问题的。如果,这里有一个需求,需要将这个折线变成平滑的曲线,那么我们应该怎么做呢。从上面讲解的知识知道,折线的过渡,可以使用贝塞尔曲线。
贝塞尔曲线的核心在于找到合适的控制点,因为控制点中,曲线一定会经过首尾两个点,那么图中的四个点,应该分别为首尾控制点。
先看一下最终绘制的曲线:
看起来确实平滑了,这四个红色的点就是上面的数据点,根据上面的结论,要让曲线经过他们,他们必须相邻的两个点为首尾控制点,那么这里使用几阶的贝塞尔合适呢。
我们以第二和第三两个点作为入手点(因为任意两个点是控制点的首尾,属于同一组控制点),要让曲线从点1平滑过渡到点2,再从点3平滑过渡到点四,那么这曲线的走势必然要受到点1,点4的影响,也就是说,两个相邻数据点之间的曲线走势,不仅受到自己的所在位置的影响,还受到前后两点的影响,加起来其实影响这段曲线走势的就有四个点。那么可以推断出来,四个点的贝塞尔曲线,当然是三阶曲线。
那么既然相邻两个数据点是控制点的首尾点,那么另外两个控制点又该如何求得呢,从上面的分析可以知道,另外两个控制点,是为了控制曲线的走势。我们先来完整控制点的图:
图中绿色的为控制点,红色的为数据点,每个数据点实际上也是控制点之一(只是首尾点),因此数据点既有红色也有绿色。可以看到点2和点3之间的两个控制点,一个靠近点2,一个靠近点3,靠近点2的控制点比点2高,靠近点3的控制点也比点3高,这是为什么呢。
先看上图,将靠近点2和点3的两个控制点分别标识为点a,和点b。
现在的问题在于,如何求的点a和点b的坐标。
点a,点b作为数据点2,和3之间的控制点,他们的作用,其实是为了体现前后数据点的连线趋势。先来看点a,点a要起到的作用就是要顺利的让数据点2平滑的过渡从数据点1来的曲线,并且要将曲线平滑的过渡到数据点3,那么点a相关的点就应该有数据点1,数据点2,以及数据点3。也就是说,点a的值应该由这3个点求出。同理,点b也会由他临近的数据点,以及该数据点前面的数据点和后面的数据点求得。也就是数据点3,数据点2,数据点4求得。
代码如下:
final float LINE_SMOOTHNESS = 0.2f;
final float firstDiffX = (currentPointX - prePreviousPointX);
final float firstDiffY = (currentPointY - prePreviousPointY);
final float secondDiffX = (nextPointX - previousPointX);
final float secondDiffY = (nextPointY - previousPointY);
final float firstControlPointX = previousPointX + (LINE_SMOOTHNESS * firstDiffX);
final float firstControlPointY = previousPointY + (LINE_SMOOTHNESS * firstDiffY);
final float secondControlPointX = currentPointX - (LINE_SMOOTHNESS * secondDiffX);
final float secondControlPointY = currentPointY - (LINE_SMOOTHNESS * secondDiffY);
path.cubicTo(firstControlPointX, firstControlPointY, secondControlPointX, secondControlPointY,currentPointX, currentPointY);
代码中,最后的path.cubicTo就是调用了四阶贝塞尔曲线的方法。其中firstControlPointX对应的是点a的x坐标,secondControlPointX对应的是点b的x坐标,currentPointX对应数据点3的x坐标。previousPointX对应了前一个数据点也就是数据点2的x坐标,prePreviousPointX对应了数据点1,nextPointX对应了数据点4。
以上的代码可以看出,点a,点b的相关点与我们之前分析的一致。那么这里除了这些数值以外,还有一个变量LINE_SMOOTHNESS,这个是做什么的呢。从它的名字可以看出,他是调整曲线的平滑程度的,值变化会引起控制点a,b的变化,从而影响曲线的形态。
final float LINE_SMOOTHNESS = 0.4f;
来看看值调整为0.2,和0.4的对比曲线:左边为0.2右边为0.4,可以根据具体需求调整值
标签:
原文地址:http://blog.csdn.net/cquwentao/article/details/51365797