在开发中,对于走势图和统计图,会有用平滑的曲线来进行展示的需求,我首先想到的就是贝塞尔曲线。那么贝塞尔曲线是啥呢,贴上两张图多看一会就明白了

图一     图二

上面图一是二阶贝塞尔曲线,图二是三阶贝塞尔去线,一阶贝塞尔曲线就是一条直线,所以就不贴图了。

贝塞尔曲线的公式我也不贴出来,还是看图来着直观(离开数学这个东西太久了,都已经忘了高数里面有没有,这曲线看起来好像跟求导什么的有关,已经完全记不清概念了哎-_-||)。从上面动图中,可以看出来要画出平滑的曲线,主要就是要找出控制点。看着上面的图,稍微想一下,其实我们就能发现,要想把一些列的散点通过贝塞尔曲线平滑的连起来,只要保证每个点的连接处曲线的“斜率”(应该是叫这个吧)是一样的就行了。

我去网上找了一下确定贝塞尔曲线控制点的公式,看完之后果然我想的差不多,只要保证每个点连接处切线斜率一样,具体的推导过程也不放出来了(这玩意儿已经看的我几脸懵逼了),直接将推导结果用代码表示出来在解释一下(下面代码都是在前篇的基础上增加和改造):

    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走势图(三、贝塞尔曲线)相关推荐

  1. 自定义view实战(10):贝塞尔曲线绘制小红点

    前言 上一篇文章用扇形图练习了一下安卓的多点触控,实现了单指旋转.二指放大.三指移动,四指以上同时按下进行复位的功能.今天这篇文章用很多应用常见的小红点,来练习一下贝塞尔曲线的使用. 需求 这里想法来 ...

  2. android自定义曲线控件,Android自定义view进阶-- 神奇的贝塞尔曲线

    上一篇介绍了自定义view需要知道的基本函数.新开一篇献给借给我vpn的深圳_奋斗小哥. 转载请注明出处:http://blog.csdn.net/wingichoy/article/details/ ...

  3. 自定义view走势图(二、加入动画和触摸事件)

    很早就想来完善之前写的走势图(一)了,结果两个月感觉天天都在忙,无脑写代码,还偶尔通宵,尼玛啊,一脸要死的样子,现在总算有点时间了~~~~ 这篇是在第一篇的基础上进行的完善和改进,主要就是加入了动画和 ...

  4. android 自定义心形,android使用贝塞尔曲线自定义心形View

    贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线. 绘制心形需要Path类中的两个方法分别是: moveTo(float x,float y) 贝塞 ...

  5. View自定义系列:最全面贝塞尔曲线详解

    1:二阶贝塞尔曲线,需要将为一阶.三阶需要将为二阶,再将为一阶.n阶需要将为n-1阶.....一直将为1阶. 自带美感的贝塞尔曲线原理与实战--Android高级UI - 掘金

  6. Android自定义View:ViewGroup(三)

    自定义ViewGroup本质是什么? 自定义ViewGroup本质上就干一件事--layout. layout 我们知道ViewGroup是一个组合View,它与普通的基本View(只要不是ViewG ...

  7. html贝塞尔曲线爱心,史上最全的贝塞尔曲线(Bezier)全解(三):贝塞尔曲线实现满屏爱心...

    这一篇文章会完整的介绍如何通过贝塞尔曲线实现爱心点赞的效果,如果实在看不懂,可以看第一篇贝塞尔曲线的简介,还有第二篇安卓中的简单使用; 好了,终于到了放大招的时候了,真实憋了很久了 这里写图片描述 先 ...

  8. 自定义View -- 蜘蛛网图

    经常会在游戏中看到用蜘蛛网图表达用户在游戏中的各种表现,感觉还蛮直观蛮有趣的,刚好最近也在学习自定义View的相关知识,就自己做一个蜘蛛网图,作为笔记了. 先放一张我感觉对自己挺有帮助,从网上找的以这 ...

  9. 图形学实验三 贝塞尔曲线、旋转曲面、扫掠曲面

    实验三 实验要求: 本次实验的内容主要为:绘制下面三种形状. 贝塞尔曲线的绘制 Surfaces of revolution Sweep Surfaces 实现思路及实现结果: 1.贝塞尔曲线 用鼠标 ...

最新文章

  1. 关于自注意力机制的思考
  2. 记一次configuration wizard运行失败
  3. 黑帽与白帽始终有着“差别”
  4. Logging with ElasticSearch, Kibana, ASP.NET Core and Docker
  5. P4707-重返现世【dp,数学期望,扩展min-max容斥】
  6. 深入解析GBDT二分类算法(附代码实现)
  7. 全面讲解OpenStack技术知识
  8. apple quicktime怎么在ppt中用_PPT情感专题大赏No. 007:一份这就是街舞第三季主题PPT(上集)...
  9. 性能测试监控关键指标
  10. 滴滴顺风车上线新功能,特殊时期便捷出行
  11. [No000011A]Office Excel设置显示日期与星期
  12. 遇到一个不得其解的问题。
  13. 百度,高德地图经纬度转换
  14. 网易云音乐等级快速升级:每天自动打卡听歌300首
  15. 20172304 《程序设计与数据结构》第五周学习总结
  16. Radare2 框架介绍及使用
  17. 通过hive sql实现报表中的MTD,YTM,YTD
  18. CRC-16 CCITT
  19. OC callback
  20. 电视不正常Android镜像投屏,Mirror for Android TV(安卓电视投屏软件) V2.4 Mac版

热门文章

  1. 解密:马云为何对肯德基“下手”?
  2. 【OTT】腾讯视频发布第一代“企鹅盒子”
  3. 立足“新时代父子关系”,海澜之家凭走心营销引起大众情感共鸣!
  4. matlab利用滑动条控制图片二值化阈值
  5. 互联网行业的高薪是真的有那么高吗?高薪还会持续多久?
  6. 彩色图片转手绘线稿的原理简述与Python实现
  7. 详解Mycat读写分离
  8. Intellij Idea 快捷键设置大全
  9. [code]自动白平衡white blance
  10. C 二级 将长整型数s中每一位上为偶数的数依次取出, 构成一个新数放在t中。 高位仍在高位,低位仍在低位。