自定义view走势图(三、贝塞尔曲线)
来源:互联网 发布:楚天消防网通知通告 编辑:程序博客网 时间:2024/04/30 09:52
在开发中,对于走势图和统计图,会有用平滑的曲线来进行展示的需求,我首先想到的就是贝塞尔曲线。那么贝塞尔曲线是啥呢,贴上两张图多看一会就明白了
图一 图二
上面图一是二阶贝塞尔曲线,图二是三阶贝塞尔去线,一阶贝塞尔曲线就是一条直线,所以就不贴图了。
贝塞尔曲线的公式我也不贴出来,还是看图来着直观(离开数学这个东西太久了,都已经忘了高数里面有没有,这曲线看起来好像跟求导什么的有关,已经完全记不清概念了哎-_-||)。从上面动图中,可以看出来要画出平滑的曲线,主要就是要找出控制点。看着上面的图,稍微想一下,其实我们就能发现,要想把一些列的散点通过贝塞尔曲线平滑的连起来,只要保证每个点的连接处曲线的“斜率”(应该是叫这个吧)是一样的就行了。
我去网上找了一下确定贝塞尔曲线控制点的公式,看完之后果然我想的差不多,只要保证每个点连接处切线斜率一样,具体的推导过程也不放出来了(这玩意儿已经看的我几脸懵逼了),直接将推导结果用代码表示出来在解释一下(下面代码都是在前篇的基础上增加和改造):
private void drawBezierLine(Canvas canvas, List<Point> pointList){ linePath.reset(); Path controlPath = new Path(); float radius = 0.13f; //曲线弧度 for(int i=0;i<xCount;i++){ Point point = pointList.get(i); Location current = getLocation(point, i); Location preLast = i >= 2 ? getLocation(pointList.get(i-2), i-2) : current; Location last = i >= 1 ? getLocation(pointList.get(i-1), i-1) : current; Location next = i == xCount -1 ? current : getLocation(pointList.get(i+1), i+1); if(i == 0){ linePath.moveTo(current.x, current.y); controlPath.moveTo(current.x, current.y); }else{ //求控制点的坐标 float firstDiffX = current.x - preLast.x; float firstDiffY = current.y - preLast.y; float secondDiffX = next.x - last.x; float secondDiffY = next.y - last.y; float firstControlX = last.x + radius * firstDiffX; float firstControlY = last.y + radius * firstDiffY; float secondControlX = current.x - radius * secondDiffX; float secondControlY = current.y - radius * secondDiffY; //保证曲线的控制点不超过坐标轴的上限和下限 firstControlY = firstControlY < top ? top : firstControlY; firstControlY = firstControlY > bottom ? bottom : firstControlY; secondControlY = secondControlY < top ? top : secondControlY; secondControlY = secondControlY > bottom ? bottom : secondControlY; //画出贝塞尔曲线 linePath.cubicTo(firstControlX, firstControlY, secondControlX, secondControlY, current.x, current.y); if(isShowControlLine){ controlPath.lineTo(firstControlX, firstControlY); controlPath.lineTo(secondControlX, secondControlY); canvas.drawCircle(firstControlX, firstControlY, 5, controlPointPaint); canvas.drawCircle(secondControlX, secondControlY, 5, controlPointPaint); } } if(isShowPoint){ canvas.drawCircle(current.x, current.y, 5f, textPaint); } } canvas.drawPath(linePath, linePaint); if(isShowControlLine){ canvas.drawPath(controlPath, controlPaint); } }
上面这个方法就是画贝塞尔曲线时调用的方法,上面用的二阶贝塞尔曲线进行连点的,根据公式,确定两个辅助点的位置需要4个点来确定,也就是上面代码中取的四个点:current(当前点),last(当前点的上一个点),perLast(当前点的上上个点),next(当前点的下一个点),关键地方就是求控制点的方法,上述方法中给出了注释,分别计算出了两个控制点的横纵坐标,其他不多说,来看下实际效果图:
float radius1 = 0.5f; float radius2; if(Math.abs(current.y - last.y) <= 8 * specY){ radius2 = 0.06f; }else{ radius2 = 0.12f; } float firstX; float firstY; float secondX; float secondY; float firstDiffX = current.x - preLast.x; float firstDiffY = current.y - preLast.y; float secondDiffX = next.x - last.x; float secondDiffY = next.y - last.y; if(last.isPeak() && current.isPeak()){ firstX = current.x - radius1 * specX; firstY = last.y; secondX = last.x + radius1 * specX; secondY = current.y; }else if(!last.isPeak() && current.isPeak()){ firstX = last.x + radius2 * firstDiffX; firstY = last.y + radius2 * firstDiffY; secondX = last.x + radius1 * specX; secondY = current.y; }else if(last.isPeak() && !current.isPeak()){ firstX = current.x - radius1 * specX; firstY = last.y; secondX = current.x - radius2 * secondDiffX; secondY = current.y - radius2 * secondDiffY; }else{ firstX = last.x + radius2 * firstDiffX; firstY = last.y + radius2 * firstDiffY; secondX = current.x - radius2 * secondDiffX; secondY = current.y - radius2 * secondDiffY; }主要改动的地方就是加了几个判断,代码中的isPeak()判断一个点是不是一个顶点,是峰顶或者峰谷的顶点,然后再来取控制点。
文字还是太干燥了,不直观,直接上图对比:
左边是修改之前,右边是修改之后,注意看每个顶点的连接处,就能发现不一样,下面我在把带控制点的两张图对比一下,区别就更明显了:
这两张图中红色部分就是算出的控制点的轨迹图,连起来之后,就相当于每个点连接处的切线。两个图最大的区别就是在顶点处的切线的斜率不一样,其他点都差不多。上面右图可以看出,在所有的顶点处切线都是水平的,这就是我改动的主要地方,保证所有顶点处切线的斜率为0。
贝塞尔曲线用起来还是不错的,关键就在控制点的计算,贝塞尔曲线的公式很复杂,但是看懂上面的图了,其实找控制点也不算太难,用心去领悟一下就行了。写这个东西的时候,太多数学的东西已经忘了,看来得回去补补了。
- 自定义view走势图(三、贝塞尔曲线)
- 自定义view画走势图(一)
- Android进阶之自定义View实战(三)贝塞尔曲线应用
- 自定义view走势图(二、加入动画和触摸事件)
- Android自定义View,贝塞尔曲线
- 自定义View之贝塞尔曲线
- Android自定义View-- 贝塞尔曲线
- android自定义View基础系列二(贝塞尔曲线)
- Android自定义View---Canvas绘制贝塞尔曲线
- 安卓自定义View进阶 - 贝塞尔曲线
- Android自定义View进阶 - 贝塞尔曲线
- 安卓自定义 View 进阶:贝塞尔曲线
- 025.自定义View中应用贝塞尔曲线
- Android自定义View贝塞尔曲线最佳实现
- 自定义View动画-贝塞尔曲线动画
- Android 自定义view实现贝塞尔曲线
- Android自定义View之贝塞尔曲线
- 自定义View练习(二)二阶贝塞尔曲线
- 各类学习网址汇总
- 时钟
- 【Nvidia Digits】运行的时候报错"TypeError: constructor returned NULL"解决办法
- javascript JSON和Object
- The Oracle system identifier(SID) "XYSPOSP" already exists. Specify another SID.
- 自定义view走势图(三、贝塞尔曲线)
- bzoj3316: JC loves Mkk
- HashSet与HashMap的关系(学习记录)
- ubuntu14.04 安装QQ国际版
- nginx安装
- 考试练习
- 使用class-dump导出头文件
- [日常问题]关于glide加载gif加载不出来或者出现卡的情况
- Robot Framework自动化测试基础实战课程 1